最近使用springboot框架做了一个项目,其中使用了shiro进行登录认证和权限管理,这里给shiro模块做一个笔记。
导入shiro依赖
1 <dependency> 2 <groupId>org.apache.shiro</groupId> 3 <artifactId>shiro-spring-boot-web-starter</artifactId> 4 <version>1.4.1</version> 5 </dependency>
User实体类
1 public class User implements Serializable{ 2 private static final long serialVersionUID = 1L; 3 private int userId; 4 private String userName; 5 private String password; 6 private boolean rememberMe; 7 private List<Role> roles; 8 //setter、getter... 9 }
Role实体类
1 public class Role { 2 private int roleId; 3 private String roleName; 4 private List<User> users; 5 private List<Resource> resources; 6 //setter、getter... 7 }
Resource实体类
1 public class Resource { 2 private int resourceId; 3 private String resourceUri; 4 private String resourceName; 5 private String permission; 6 private List<Role> roles; 7 //setter、getter 8 }
自定义Realm
1 @Component 2 public class MyRealm extends AuthorizingRealm { 3 @Autowired 4 private ResourceService resourceService; 5 @Autowired 6 private UserService userService; 7 8 9 10 /** 11 * 给用户授权 12 */ 13 @Override 14 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 15 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); 16 //获取用户对象 17 User user = (User) principalCollection.getPrimaryPrincipal(); 18 //获取用户的角色信息 19 List<Role> roles = user.getRoles(); 20 if (roles != null && !roles.isEmpty()) { 21 //遍历当前用户的所有角色,将角色名添加到用户权限中 22 roles.forEach(role -> { 23 simpleAuthorizationInfo.addRole(role.getRoleName()); 24 //获取每个角色能访问的资源 25 List<Resource> resources = 26 resourceService.getResourcesByRoleId(role.getRoleId()); 27 if (resources != null && !resources.isEmpty()) { 28 //遍历当角色所能访问的资源,将资源的uri添加到用户权限中 29 resources.forEach(resource -> 30 simpleAuthorizationInfo.addStringPermission(resource.getResourceUri())); 31 } 32 }); 33 } 34 return simpleAuthorizationInfo; 35 } 36 37 /** 38 * 用户认证 39 */ 40 @Override 41 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { 42 //获取令牌(即用户名) 43 String userName = (String) authenticationToken.getPrincipal(); 44 //获取数据库中的用户信息,用于比对 45 User user = userService.getUserByUserName(userName); 46 if(user == null) { 47 throw new UnknownAccountException("用户名不存在"); 48 } 49 50 //设置盐 51 ByteSource salt = ByteSource.Util.bytes(userName+ MD5Util.getSALT()); 52 53 return new SimpleAuthenticationInfo(user,user.getPassword(),salt,getName()); 54 } 55 56 57 }
shiro配置类
1 @Configuration 2 @Component 3 public class ShiroConfig { 4 5 6 /** 7 * 配置Realm 8 */ 9 @Bean 10 public MyRealm realm() { 11 12 MyRealm myRealm = new MyRealm(); 13 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); 14 //设置加密方式 15 hashedCredentialsMatcher.setHashAlgorithmName("MD5"); 16 //设置加密次数 17 hashedCredentialsMatcher.setHashIterations(1024); 18 myRealm.setCredentialsMatcher(hashedCredentialsMatcher); 19 20 return myRealm; 21 } 22 23 /** 24 * 注册默认的安全管理器 25 */ 26 @Bean 27 public DefaultSecurityManager securityManager() { 28 DefaultSecurityManager manager = new DefaultWebSecurityManager(); 29 manager.setRealm(realm()); 30 return manager; 31 } 32 33 /** 34 * 配置shiro过滤器工厂 35 * ----------------- 36 * 拦截权限 37 * anon:匿名访问,无需登录 38 * authc:登录后才能访问 39 * user:登录过能访问 40 * logout:登出 41 * roles:角色过滤器 42 * ------------------ 43 * URL匹配风格 44 * ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin 或 /admin/ 45 * *:匹配零个或多个字符串,如 /admin* 将匹配 /admin 或/admin123,但不匹配 /admin/1 46 * **:匹配路径中的零个或多个路径,如 /admin/** 将匹配 /admin/a 或 /admin/a/b 47 * ----------------------- 48 * 方法名不能乱写,如果我们定义为别的名称,又没有添加注册过滤器的配置,那么shiro会加载ShiroWebFilterConfiguration过滤器, 49 * 该过滤器会寻找shiroFilterFactoryBean,找不到会抛出异常 50 */ 51 @Bean 52 public ShiroFilterFactoryBean shiroFilterFactoryBean() { 53 ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); 54 shiroFilter.setSecurityManager(securityManager()); 55 56 shiroFilter.setLoginUrl("/account/loginVue"); 57 shiroFilter.setSuccessUrl("/account/dashboard"); 58 59 Map<String,String> map = new LinkedHashMap<>(); 60 map.put("/", "authc"); 61 map.put("/static/**", "anon"); 62 map.put("/js/**", "anon"); 63 map.put("/css/**", "anon"); 64 map.put("/plugin/**", "anon"); 65 map.put("/account/login", "anon"); 66 map.put("/account/loginVue", "anon"); 67 map.put("/api/login", "anon"); 68 map.put("/account/register", "anon"); 69 map.put("/account/registerVue", "anon"); 70 map.put("/api/user", "anon"); 71 72 map.put("/common/**", "user"); 73 map.put("/test/**", "user"); 74 map.put("/**", "authc"); 75 76 shiroFilter.setFilterChainDefinitionMap(map); 77 78 return shiroFilter; 79 } 80 81 /** 82 * 注册ShiroDialect,让thymeleaf支持shiro标签 83 */ 84 @Bean 85 public ShiroDialect shiroDialect() { 86 return new ShiroDialect(); 87 } 88 89 /** 90 * 自动代理类,支持Shiro的注解 91 */ 92 @Bean 93 @DependsOn({"lifecycleBeanPostProcessor"}) 94 public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){ 95 DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = 96 new DefaultAdvisorAutoProxyCreator(); 97 advisorAutoProxyCreator.setProxyTargetClass(true); 98 return advisorAutoProxyCreator; 99 } 100 101 /** 102 * 开启Shiro的注解 103 */ 104 @Bean 105 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){ 106 AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = 107 new AuthorizationAttributeSourceAdvisor(); 108 authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); 109 return authorizationAttributeSourceAdvisor; 110 } 111 }
UserServiceImpl类
1 @Service 2 public class UserServiceImpl implements UserService { 3 4 @Override 5 public Result<User> login(User user) { 6 //获取当前的用户 7 Subject subject = SecurityUtils.getSubject(); 8 9 //将传来的user信息封装到UsernamePasswordToken 10 UsernamePasswordToken usernamePasswordToken = 11 new UsernamePasswordToken(user.getUserName(), 12 user.getPassword()); 13 usernamePasswordToken.setRememberMe(user.getRememberMe()); 14 15 try { 16 //登录验证 17 subject.login(usernamePasswordToken); 18 subject.checkRoles(); 19 } catch (AuthenticationException e) { 20 e.printStackTrace(); 21 return new Result<>(Result.ResultStatus.FAILED.status, 22 "用户名或密码错误"); 23 } 24 25 //将用户信息加入到session里 26 Session session = subject.getSession(); 27 session.setAttribute("user",subject.getPrincipal()); 28 return new Result<>(Result.ResultStatus.SUCCESS.status, 29 "登录成功", user); 30 } 31 32 @Override 33 public void logout() { 34 Subject subject = SecurityUtils.getSubject(); 35 subject.logout(); 36 Session session = subject.getSession(); 37 session.removeAttribute("user"); 38 } 39 }
浙公网安备 33010602011771号