当前位置: 首页 > 工具软件 > Jive > 使用案例 >

三、jive系统设计(3 Jive安全管理机制)

庄兴发
2023-12-01

3  Jive安全管理机制

Jive中除了前面介绍的有关设计模式实现组件外,还有其他有一定特点的组件功能,分析研究这些组件功能可以更加完整透彻地理解Jive论坛系统。

Jive安全管理机制基本是由下列部分组成:

·          安全验证机制。主要是验证用户名和密码组合是否与数据库中注册时的数据一致,以确认该用户身份为注册用户。这是对所有的JSP访问都进行拦截访问。

·          访问权限控制(ACL)。对不同的数据不同用户拥有不同的访问权限,例如,一个帖子普通用户可以浏览,但是不能更改;但是管理员却可以编辑删除。这部分功能是通过代理模式实现,为每个关键数据都建立一个代理类用来实现访问权限检查,这在前面讨论过。

·          用户资料管理系统。主要是管理用户的资料数据,进行用户组和用户关系的建立等。

1  安全验证机制

Jive的安全验证机制是按照比较通用的思路设计的。类似前面“简单的用户注册管理系统”中的介绍,Jive也是在所有的JSP页面中include一个安全检验功能的global.jsp。由于global.jsp是在每个JSP一开始必须执行的功能,因此通过拦截global.jsp拦截发往各个JSP页面的请求(request)。如果这个请求是合法的,将被允许通过;如果不是,将注明请求者身份是Anonymous(匿名者)。

global.jsp代码如下:

boolean isGuest = false;
Authorization authToken = SkinUtils.getUserAuthorization(request, response);
if (authToken == null) {//未被验证通过
    authToken = AuthorizationFactory.getAnonymousAuthorization();
    isGuest=true;
}

Jive中,以Authorization对象作为验证通过的标志,它的接口代码如下:

public interface Authorization {
    public long getUserID();   
    public boolean isAnonymous();
}

具体实现是DbAuthorization,代码如下:

public final class DbAuthorization implements Authorization, Serializable {
    private long userID;
    protected DbAuthorization(long userID) {
        this.userID = userID;
    }
    public long getUserID() {
        return userID;
    }
    public boolean isAnonymous() {
        return userID == -1;
    }
}

此类只是一个userID,因此只是一个象征性的标志。

SkinUtils是一个为JSP服务的类,它的getUserAuthorization代码如下:

public static Authorization getUserAuthorization
        (HttpServletRequest request, HttpServletResponse response)
  {
    HttpSession session = request.getSession();
    // 从HttpSession中获取Authorization实例
    Authorization authToken =
(Authorization)session.getAttribute(JIVE_AUTH_TOKEN);
    if (authToken != null) {     return authToken;  }
 
    // 如果HttpSession中没有,检查用户浏览器cookie
    Cookie cookie = getCookie(request, JIVE_AUTOLOGIN_COOKIE);
    if (cookie != null) {
        try {
           String[] values = decodePasswordCookie(cookie.getValue());
           String username = values[0];
           String password = values[1];
           //从cookie中获得用户名和密码后,进行安全验证
           authToken = AuthorizationFactory.getAuthorization(username,password);
        }catch (Exception e) {}
        // put that token in the user's session:
        if (authToken != null) {//如果通过验证,保存authToken在http Session
           session.setAttribute(JIVE_AUTH_TOKEN, authToken);
        }
       // return the authorization token
        return authToken;
    }
    return null;
}

用户验证预先通过两个步骤。首先检查HttpSession中是否保存了该用户的验证信息,如果用户第一次验证通过,反复访问,这道关口检查就可以通过。

如果HttpSession中没有验证信息,那么从该用户的浏览器cookie中寻找用户名和密码。如果该用户激活了cookie保存这些登录信息,那么应该可以找到用户名和密码,这样就省却了用户再次从键盘输入用户名和密码,将用户名和密码通过下列语句进行数据库验证:

authToken = AuthorizationFactory.getAuthorization(username,password);

这一举是验证关键。AuthorizationFactory是一个抽象类,定义了Jive安全验证机制所需的所有方法,AuthorizationFactory的实现类似前面讨论的ForumFactory实现,是使用工厂模式加动态类反射机制完成的,代码如下:

public abstract class AuthorizationFactory {
   //定义一个数据库具体实现
    private static String className =
        " com.Yasna.forum.database.DbAuthorizationFactory";
 
    private static AuthorizationFactory factory = null;
    //验证方法 如果没有UnauthorizedException抛出,表示验证通过
    public static Authorization getAuthorization(String username,
            String password) throws UnauthorizedException
    {
        loadAuthorizationFactory();
        return factory.createAuthorization(username, password);
    }
    //匿名者处理方法
    public static Authorization getAnonymousAuthorization() {
        loadAuthorizationFactory();
        return factory.createAnonymousAuthorization();
    }
    //需要具体实现的抽象方法
    protected abstract Authorization createAuthorization(String username,
            String password) throws UnauthorizedException;
    protected abstract Authorization createAnonymousAuthorization();
    //动态配置AuthorizationFactory的具体实现,可以在配置文件中定义一个
    //基于LDAP的实现。类似ForumFactory的getInstance方法
    private static void loadAuthorizationFactory() {
        …
    }
}

AuthorizationFactory看上去很复杂,实际只有一个核心方法getAuthorization。实现用户名和密码的验证。如果无法通过验证,有两个信息实现显示:一个是抛出UnauthorizedException,另外一个是返回空的Authorization对象。

那么,子类DbAuthorizationFactory毫无疑问就是查询数据库,将输入的用户名和密码与数据库保存的用户名和密码进行校验。

Jive的安全验证机制比较简单易懂,值得在实践中学习借鉴。但是注意到这套安全验证机制只是Web层的“手工”验证,资源访问权限(ACL)也是自己“手工”来实现的。如果使用EJB技术,因为EJB容器本身有一定的资源访问控制体系,因此在Web层验证通过后,需要将这些登录信息传递到EJB层。当然如果直接使用Web容器的安全验证机制,那么Web层与EJB层之间的登录信息传递将由容器实现,这样就更加简单方便。

Jive这种的安全验证并不是使用Web容器的安全验证机制,如何使用Web容器的安全验证机制将在以后章节介绍。尽管如此,Jive这套安全验证机制对付小型系统的应用也是足够的。


2  用户资料管理

Jive中,用户User对象的操作访问类似于论坛Forum对象的访问,与User对象有关的操作都封装在一个类中操作,这是外观(Facade)模式的应用。

Jive中,用户资料管理属于大系统中的一个子系统,在这个子系统中,用户子系统和其他系统又有一定的关系,涉及的类不少,通过建立一个UserManager类来统一对外接口,使得整个子系统条目结构清晰。

UserManager中无外乎用户数据的管理,如用户的创建、修改、查询和删除。DbUserManagerUserManager的一个数据库实现,可是看看DbUserManager中除了删除功能是直接通过SQL语句进行数据库删除操作外,其他都委托给User的具体实现DbUser实现的。这种实现非常类似于EJBSession Bean和实体Bean之间的关系。以创建用户资料为例,代码如下:

public User createUser(String username, String password, String email)
            throws UserAlreadyExistsException
 {
        User newUser = null;
        try {
            //以username查询改用户是否存在
            User existingUser = getUser(username);
            //如果没有抛出UserNotFoundException异常,表示该用户存在
            //The user already exists since now exception, so:
            throw new UserAlreadyExistsException();
        } catch (UserNotFoundException unfe) {
            //该用户不存在,创建一个新用户
            newUser = new DbUser(username, password, email, factory);
        }
        return newUser;
}
DbUser的构造方法实际是用户资料的新增创建:
protected DbUser(String username, String password, String email,
            DbForumFactory factory)
{
        this.id = SequenceManager.nextID(JiveGlobals.USER);  //获得自增ID
        this.username = username;
        // Compute hash of password.
        this.passwordHash = StringUtils.hash(password);  //获得加密的密码
        this.email = email;
        this.factory = factory;
        long now = System.currentTimeMillis();
        creationDate = new java.util.Date(now);
        modifiedDate = new java.util.Date(now);
        properties = new Hashtable();
        insertIntoDb();              //数据库插入数据
}

Jive中,数据修改的保存是由DbUsersaveToDb方法实现的,而saveToDb方法调用是在每个setXXXX方法中。即每当外界调用DbUsersetXXXX,则表示需要改变某些字段属性值,在这个方法中直接进行数据库存储,这也类似EJBCMP实体Bean的数据字段修改保存。

Jive中组Group与用户User处理几乎差不多,只是在Group中整合了权限方面的信息,这种做法是有一定的局限性,不是很值得借鉴,要想设计一个动态扩展灵活的权限系统,必须在用户或组与权限之间引入角色概念,也就是比较先进的基于角色的权限系统(RBAC Roled-Based Access Control,相关网址:

http://csrc.nist.gov/rbac/

)。

RBAC中,用户组只是用户的一个集合,应该是通过角色和权限发生联系。所以RBAC认为,如果给用户组赋予权限,那么用户组也接近角色的概念。



转载于:https://my.oschina.net/pamgo/blog/652267

 类似资料: