在上一个笔记中我们实现了用户认证,那么接下来我们实现用户授权,看一下流程图.
这个流程图就是上一个笔记中的图, 我截取的部分就是用户授权的流程
在流程图中我们看到有一个授权过滤器拦截获取访问URL,所以我们就需要创建这个拦截器,然后在拦截器中,进行下面流程操作.
我们可以看到有一个URL是否公开地址这个与我们上一个笔记中的公开地址是不一样的.
这个配置文件的所用是,让授权过滤器不对配置文件中的URL分配访问权限,可以允许直接访问.
可能有人会想在做用户认证的时候有一个公开地址,用户授权的时候也有一个公开地址,这两个公开地址不能使用同一个吗?
答:用户认证时候的那个公开地址,就是我们没有用户认证通过就能访问的地址,比如: 系统登录的URL.
而这个用户授权的公开地址是 我们已经通过用户认证了,进入后台,但是由于不同角色登录系统后有不同的权限,所以我们需要做一些限制,哪些权限能访问哪些URL地址.而所有权限都能访问的地址,我们就将这些地址放到公开URL配置文件中.
创建公开地址配置文件
我们创建一个名为commonURL.properties
的文件来存放我们的URL公开地址.
我们在这个文件中配置两条数据
login.action=退出
如果用户访问的URL在公共访问地址中那么就可以直接访问,如果不在就会判断用户访问的这个URL在不在他的权限中,如果在那么可以访问,如果不在就提示无权操作.
但是这里要注意, 我们的权限是存在数据库中,而授权过滤器每次都要拦截用户访问的URL进行判断,那么就意味着我们每次都要操作数据库,但是如果我们每次都去操作数据库这也就意味着会降低系统性能.
所以我们的解决方案就是,在用户认证通过后将权限取出,放到session中或缓存中.
获取用户权限范围的URL与用户菜单
思路: 在用户认证通过后,根据用户id从数据库获取用户权限范围的url,然后将url的集合存储在session中.
SQL语句
SELECT
*
FROM
sys_permission
WHERE TYPE = #{type}
AND id IN
(SELECT
sys_permission_id
FROM
sys_role_permission
WHERE sys_role_id IN
(SELECT
sys_role_id
FROM
sys_user_role
WHERE sys_user_id = #{id}))
参数 type: 如果要查询权限就写permission 如果要查询菜单就写menu
参数 id: 用户id
然后在service中查询出来,将菜单和url放入你创建的ActiveUser对象中,再将这个对象放入session中.
上面的这些操作就是取出我们要的数据,并且放到session中了,接下来就是判断了.
最终代码
//在执行handler之前来执行的
//用于用户认证校验、用户权限校验
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//得到请求的url
String url = request.getRequestURI();
//判断是否是公开 地址
//实际开发中需要公开 地址配置在配置文件中
//从配置中取逆名访问url
List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL");
//遍历公开 地址,如果是公开 地址则放行
for(String open_url:open_urls){
if(url.indexOf(open_url)>=0){
//如果是公开 地址则放行
return true;
}
}
//从配置文件中获取公共访问地址
List<String> common_urls = ResourcesUtil.gekeyList("commonURL");
//遍历公用 地址,如果是公用 地址则放行
for(String common_url:common_urls){
if(url.indexOf(common_url)>=0){
//如果是公开 地址则放行
return true;
}
}
//获取session
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
//从session中取权限范围的url
List<SysPermission> permissions = activeUser.getPermissions();
for(SysPermission sysPermission:permissions){
//权限的url
String permission_url = sysPermission.getUrl();
if(url.indexOf(permission_url)>=0){
//如果是权限的url 地址则放行
return true;
}
}
//执行到这里拦截,跳转到无权访问的提示页面
request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
//如果返回false表示拦截不继续执行handler,如果返回true表示放行
return false;
}
配置授权拦截器
注意:将授权连接器配置在用户认证拦截器的下边.
<!--拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 用户认证拦截 -->
<mvc:mapping path="/**" />
<bean class="cn.xxx.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 授权拦截 -->
<mvc:mapping path="/**" />
<bean class="cn.xxx.interceptor.PermissionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
这样就做完了,但是这种方式有好处也有坏处
好处:实现起来比较简单,不依赖框架,使用web提供的filter就可以实现.
坏处:需要将所有的url全部配置起来(放入数据库和公共文件中),这样做有些繁琐,不容易维护.