接上一篇内容,对之前的配置文件做一些修改。
在web.xml中加入编码格式过滤器,从而就可以正常接收中文字符。
1 <filter> 2 <filter-name>characterEncodingFilter</filter-name> 3 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 4 <init-param> 5 <param-name>encoding</param-name> 6 <param-value>UTF-8</param-value> 7 </init-param> 8 </filter> 9 10 <filter-mapping> 11 <filter-name>characterEncodingFilter</filter-name> 12 <url-pattern>/*</url-pattern> 13 </filter-mapping>
在applicationContext.xml的权限配置部分,加入一条:
/config/**=anon
先将配置用户角色权限的路径设置为可匿名访问。
然后还需要对DatabaseRealm中的代码稍加修改。
DatabaseRealm.java
1 public class DatabaseRealm extends AuthorizingRealm { 2 @Autowired 3 private RoleService roleService; 4 @Autowired 5 private PermissionService permissionService; 6 @Autowired 7 private UserService userService; 8 9 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 10 //能进入到这里,表示账号已经通过认证了 11 String username = (String) principals.getPrimaryPrincipal(); 12 //通过Dao获取角色和权限 13 // Set<String> permissions = new Dao().listPermissions(username); 14 // Set<String> roles = new Dao().listRoles(username); 15 Set<String> roleNames = roleService.listRoleNames(username); 16 Set<String> permisionNames = permissionService.listPermissions(username); 17 //授权对象 18 SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo(); 19 System.out.println("roles->:"+roleNames); 20 System.out.println("perms->"+permisionNames); 21 //把通过Dao获取到的角色和权限都放进去 22 sai.setStringPermissions(permisionNames); 23 sai.setRoles(roleNames); 24 return sai; 25 26 } 27 28 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 29 //获取账号密码 30 UsernamePasswordToken upt = (UsernamePasswordToken) token; 31 String username = token.getPrincipal().toString(); 32 String password = new String(upt.getPassword()); 33 String encryptPassword = ""; 34 //获取数据库中的密码 35 // User user = new Dao().getUser(username); 36 // System.out.println("进到这里了:databaserealm"); 37 User user = userService.getByName(username); 38 if(user != null) { 39 String passwordInDB = user.getPassword(); 40 String salt = user.getSalt(); 41 //将传入的密码进行加盐 42 encryptPassword = new SimpleHash("md5",password,user.getSalt(),2).toString(); 43 System.out.println("输入的密码:"+encryptPassword); 44 System.out.println("passwordInDB"+user.getPassword()); 45 } 46 47 //如果为空就是账号不存在,如果不相同就是密码错误,但是都抛出AuthenticationException,而不抛出具体错误原因,以防给破解者提供帮助信息 48 if (null == user || !encryptPassword.equals(user.getPassword())) { 49 throw new AuthenticationException(); 50 } 51 //认证信息里存放账号和密码,getName()是当前Realm的继承方法,通常返回当前类名:DatabaseRealm 52 SimpleAuthenticationInfo sai = new SimpleAuthenticationInfo(username,password,getName()); 53 return sai; 54 } 55 }
将之前写的index.jsp稍加修改:
1 <%@ page language="java" contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <head> 4 <link rel="stylesheet" href="static/css/style.css"/> 5 </head> 6 7 <body> 8 <div class="workingroom"> 9 <div class="loginDiv"> 10 ${request.contextPath} 11 <c:if test="${!empty subject.principal}"> 12 <span>你好!${subject.principal}</span> 13 <a href="doLogout">退出</a> 14 </c:if> 15 <c:if test="${empty subject.principal}"> 16 <a href="login">登录</a> 17 </c:if> 18 </div> 19 <ul> 20 <li><a href="listProduct">查看产品</a></li> 21 <li><a href="deleteProduct">删除产品</a></li> 22 <li><a href="deleteOrder">删除订单</a></li> 23 <li><a href="config/listUser">用户管理</a></li> 24 </ul> 25 26 </div> 27 </body>
重启服务器,访问:http://localhost:8080/shiro/index
到这里为止,我们的权限控制依然是由@RequiresRole,@RequiresPermission控制的,接下来对这个部分进行改造,通过动态配置url的方式完成权限控制。
1.首先去掉之前在pageController中添加的权限角色注解
2.在PermissionService中增加两个方法
needInterceptor,listPermissionURLs
在PermissionServiceImpl中的实现:
@Override public boolean needInterceptor(String requestURI) { List<Permission> permissions = list(); for (Permission permission : permissions) { if(permission.getUrl().equals(requestURI)) return true; } return false; } @Override public Set<String> listPermissionURLs(String username) { List<Role> roles = roleService.listRoles(username); Set<String> urls = new HashSet<>(); List<RolePermission> rolePermissions = new ArrayList<>(); for (Role role : roles) { RolePermissionExample example = new RolePermissionExample(); example.createCriteria().andRidEqualTo(role.getId()); List<RolePermission> temp = rolePermissionMapper.selectByExample(example); rolePermissions.addAll(temp); } for (RolePermission rolePermission : rolePermissions) { Permission permission = permissionMapper.selectByPrimaryKey(rolePermission.getPid()); urls.add(permission.getUrl()); } return urls; }
3.URLPathMatchingFilter.java
PathMatchingFilter是Shiro的内置过滤器,我们自定义一个URLPathMathingFilter继承这个过滤器。
基本思路如下:
1.如果没有登录,跳转到登录页面
2.如果访问的路径不在权限系统中所维护,允许访问
3.如果用户所属的角色没有当前路径的权限,不允许访问,跳转到/unauthorized,否则允许访问。
1 public class URLPathMatchingFilter extends PathMatchingFilter { 2 @Autowired 3 PermissionService permissionService; 4 @Override 5 protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { 6 String requestURI = getPathWithinApplication(request); 7 //判断是否登录 8 Subject subject = SecurityUtils.getSubject(); 9 if (!subject.isAuthenticated()) { 10 //如果没有登录,跳转到登录页面 11 WebUtils.issueRedirect(request, response, "/login"); 12 return false; 13 } 14 //如果已经登录,判断是否是在Permission表中维护的路径 15 if(!permissionService.needInterceptor(requestURI)) { 16 //如果不是的话,允许访问 17 return true; 18 } else { 19 //判断登录用户的角色是否拥有该路径的权限 20 boolean hasPermission = false; 21 String username = subject.getPrincipal().toString(); 22 Set<String> urls = permissionService.listPermissionURLs(username); 23 for (String url : urls) { 24 if(url.equals(requestURI)){ 25 hasPermission = true; 26 break; 27 } 28 } 29 if(hasPermission) { 30 return true; 31 } else { 32 //权限不足 33 UnauthorizedException ex = new UnauthorizedException("当前用户没有权限访问路径:" + requestURI); 34 WebUtils.issueRedirect(request,response,"/authorized"); 35 return false; 36 } 37 } 38 } 39 }
在Spring配置文件中声明URLPathMatchingFilter过滤器:
1 <!--路径匹配过滤器--> 2 <bean id="urlfilter" class="com.vi.filter.URLPathMatchingFilter"/>
在shiro过滤器工厂类中配置这个过滤器,设置过滤规则为所有url
1 <property name="filters"> 2 <util:map> 3 <entry key="logout" value-ref="logoutFilter"/> 4 <entry key="url" value-ref="urlfilter"/> 5 </util:map> 6 </property>
1 public class URLPathMatchingFilter extends PathMatchingFilter { 2 @Autowired 3 PermissionService permissionService; 4 @Override 5 protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { 6 String requestURI = getPathWithinApplication(request); 7 System.out.println("debug:"+requestURI); 8 //判断是否登录 9 Subject subject = SecurityUtils.getSubject(); 10 if (!subject.isAuthenticated()) { 11 //如果没有登录,跳转到登录页面 12 WebUtils.issueRedirect(request, response, "/login"); 13 return false; 14 } 15 //如果已经登录,判断是否是在Permission表中维护的路径 16 if(!permissionService.needInterceptor(requestURI)) { 17 //如果不是的话,允许访问 18 return true; 19 } else { 20 //判断登录用户的角色是否拥有该路径的权限 21 boolean hasPermission = false; 22 String username = subject.getPrincipal().toString(); 23 Set<String> urls = permissionService.listPermissionURLs(username); 24 for (String url : urls) { 25 if(url.equals(requestURI)){ 26 hasPermission = true; 27 break; 28 } 29 } 30 if(hasPermission) { 31 return true; 32 } else { 33 //权限不足 34 UnauthorizedException ex = new UnauthorizedException("当前用户没有权限访问路径:" + requestURI);
subject.getSession().setAttribte("ex",ex); 35 WebUtils.issueRedirect(request,response,"/unauthorized"); 36 return false; 37 } 38 } 39 } 40 }
完成以后,重启tomcat,接下来就可以动态的对访问权限进行控制了。
我们可以把用户管理,角色管理,权限管理所对应的路径全部赋给admin。这样角色不是admin的就不能够访问了。