用户权限控制几乎是每个网站都会涉及到的问题,这不仅是涉及到安全,而且还涉及到用户的体验,例如,某个用户可能只需要用到少数几个模块,那么,我们就不应该将无关的模块显示给他。对于很多的小型网站,可能只需要一个管理员账号和密码就可以了,但对于稍微大一点的网站,都会有一套比较严格的用户权限管理机制。
(1)建立数据表
基于角色和资源是目前较为常见的一种实现,一般会有以下几张表:
用户表(users):id、用户名、密码、状态(是否可用,下同)
角色表(roles):id、角色名、角色描述、角色状态
权限表(permissions):id、权限名、权限状态
除了这三张表外,还要两张表来将三者关联起来:
用户角色关联表(users_roles):用户id、角色id(复合主键)
角色权限关联表(roles_permissions):角色id、权限id(复合主键)
在Web环境中,“资源”大部分情况就是指用户是否有权限访问某个URL。为了实现更加灵活的配置,我们在上述提到的几张表基础上,再增加两张表:
资源表(resources):id、URL、描述
权限资源关联表(permissions_resources):权限id、资源id(复合主键)
(2)大体思路
(1)系统启动的时候,建立一个Map<String,Set> resourceMap,键名为resource(即URL),键值为跟该resource关联的所有permission。由于一个资源可能对应多个permission(如文章查看权限可以授予一般用户,同时也授予文章管理员),因此这里需要用到一个集合。
(2)当用户登录的时候,获取该用户所对应的角色,再根据角色获取其拥有的permission集合
(3)当用户访问受限资源的时候,通过URL从resourceMap中获取所需的permission集合,再跟该用户拥有的permission集合比对,用户有相应的permission则通过,否则不通过。
a:启动的时候建立resourceMap
b:用户登录的时候加载用户的权限并放到Session
c:创建拦截器,对相关资源进行控制
d:Spring配置
<mvc:interceptors>
定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的
<mvc:interceptor>
<mvc:mapping path="admin/**"/>
<mvc:mapping path="book/**"/>
<mvc:mapping path="examPaper/**"/>
<mvc:mapping path="lesson/**"/>
<mvc:mapping path="/**"/>
<mvc:mapping path="question/**"/>
<mvc:mapping path="role/**"/>
<mvc:mapping path="user/**"/>
<bean id="loginInceptor" class="com.bookmanager.interceptor.LoginInterceptor">
</bean>
</mvc:interceptor>
使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求
<bean id="loginInceptor" class="com.bookmanager.interceptor.LoginInterceptor">
</bean>
</mvc:interceptors>
总结:
如果你系统本身不复杂的话,不需要对某个模块的增删改进行细分,其实也可以省掉resource表,直接使用URL作为permission,然后role跟permission对应就可以了。这种实现方式的好处是可以对资源进行很精确的配置,除了上述方式,还可以采用粗粒度的配置(如将文章管理作为一项资源uc/articles,包括增删改查),或者更加细粒度的配置(如针对URL的请求方法POST、GET、PUT、DELETE),不过也有一个问题,就是当系统的资源很多的时候,在进行用户权限比对的时候会有较大的消耗。这时候,可以考虑对资源和用户进行分组,先进行分组匹配,再查找相关资源。
还可以只有一张用户表,添加一个权限字段(permission),添加管理员时将所有模块列出,进行更自由的选择,将选择的模块按约定的格式存在permission,进入每个模块时进行比对
还可以用第三方安全库,Spring scurity