每日一得

不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速开发
最近关心的内容:SSH,seam,flex,敏捷,TDD
本站的官方站点是:颠覆软件

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  220 随笔 :: 9 文章 :: 421 评论 :: 0 Trackbacks

3  Jive 安全管理机制

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

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

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

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

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

安全验证机制

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 这套安全验证机制对付小型系统的应用也是足够的。


用户资料管理

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

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

UserManager 中无外乎用户数据的管理,如用户的创建、修改、查询和删除。 DbUserManager UserManager 的一个数据库实现,可是看看 DbUserManager 中除了删除功能是直接通过 SQL 语句进行数据库删除操作外,其他都委托给 User 的具体实现 DbUser 实现的。这种实现非常类似于 EJB Session 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 中,数据修改的保存是由 DbUser saveToDb 方法实现的,而 saveToDb 方法调用是在每个 setXXXX 方法中。即每当外界调用 DbUser setXXXX ,则表示需要改变某些字段属性值,在这个方法中直接进行数据库存储,这也类似 EJB CMP 实体 Bean 的数据字段修改保存。

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

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

posted on 2006-08-31 12:26 Alex 阅读(677) 评论(0)  编辑  收藏 所属分类: java

只有注册用户登录后才能发表评论。


网站导航: