Springboot 快速集成 Shiro权限管理
SpringBoot2.0集成Shiro
数据库表结构:
1 /* 2 Navicat Premium Data Transfer 3 4 Source Server : 本机MySQL 5 Source Server Type : MySQL 6 Source Server Version : 50527 7 Source Host : localhost:3306 8 Source Schema : shiro3 9 10 Target Server Type : MySQL 11 Target Server Version : 50527 12 File Encoding : 65001 13 14 Date: 30/06/2020 16:49:48 15 */ 16 17 SET NAMES utf8mb4; 18 SET FOREIGN_KEY_CHECKS = 0; 19 20 -- ---------------------------- 21 -- Table structure for sys_permissions 22 -- ---------------------------- 23 DROP TABLE IF EXISTS `sys_permissions`; 24 CREATE TABLE `sys_permissions` ( 25 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 26 `permission` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限编号', 27 `description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限描述', 28 `rid` bigint(20) NULL DEFAULT NULL COMMENT '此权限关联角色的id', 29 `available` tinyint(1) NULL DEFAULT 0 COMMENT '是否锁定', 30 PRIMARY KEY (`id`) USING BTREE, 31 UNIQUE INDEX `idx_sys_permissions_permission`(`permission`) USING BTREE 32 ) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 33 34 -- ---------------------------- 35 -- Table structure for sys_roles 36 -- ---------------------------- 37 DROP TABLE IF EXISTS `sys_roles`; 38 CREATE TABLE `sys_roles` ( 39 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色编号', 40 `role` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名称', 41 `description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色描述', 42 `pid` bigint(20) NULL DEFAULT NULL COMMENT '父节点', 43 `available` tinyint(1) NULL DEFAULT 0 COMMENT '是否锁定', 44 PRIMARY KEY (`id`) USING BTREE, 45 UNIQUE INDEX `idx_sys_roles_role`(`role`) USING BTREE 46 ) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 47 48 -- ---------------------------- 49 -- Table structure for sys_roles_permissions 50 -- ---------------------------- 51 DROP TABLE IF EXISTS `sys_roles_permissions`; 52 CREATE TABLE `sys_roles_permissions` ( 53 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 54 `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色编号', 55 `permission_id` bigint(20) NULL DEFAULT NULL COMMENT '权限编号', 56 PRIMARY KEY (`id`) USING BTREE 57 ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 58 59 -- ---------------------------- 60 -- Table structure for sys_users 61 -- ---------------------------- 62 DROP TABLE IF EXISTS `sys_users`; 63 CREATE TABLE `sys_users` ( 64 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 65 `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名', 66 `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码', 67 `salt` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '盐值', 68 `role_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色列表', 69 `locked` tinyint(1) NULL DEFAULT 0 COMMENT '是否锁定', 70 PRIMARY KEY (`id`) USING BTREE, 71 UNIQUE INDEX `idx_sys_users_username`(`username`) USING BTREE 72 ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 73 74 -- ---------------------------- 75 -- Table structure for sys_users_roles 76 -- ---------------------------- 77 DROP TABLE IF EXISTS `sys_users_roles`; 78 CREATE TABLE `sys_users_roles` ( 79 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 80 `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户编号', 81 `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色编号', 82 PRIMARY KEY (`id`) USING BTREE 83 ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 84 85 SET FOREIGN_KEY_CHECKS = 1;
项目版本:
1 springboot2.x 2 shiro:1.3.2
Maven依赖:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
springboot中集成shiro相对简单,只需要两个类:一个是shiroConfig类,一个是CustonRealm类。
ShiroConfig类:
顾名思义就是对shiro的一些配置,相对于之前的xml配置。包括:过滤的文件和权限,密码加密的算法,其用注解等相关功能。
CustomRealm类:
自定义的CustomRealm继承AuthorizingRealm。并且重写父类中的doGetAuthorizationInfo(权限相关)、doGetAuthenticationInfo(身份认证)这两个方法。
项目结构:
shiroConfig配置:
1 package com.SC.demo.utils; 2 3 import java.util.LinkedHashMap; 4 import java.util.Map; 5 6 import org.apache.shiro.authc.credential.HashedCredentialsMatcher; 7 import org.apache.shiro.mgt.SecurityManager; 8 import org.apache.shiro.spring.LifecycleBeanPostProcessor; 9 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; 10 import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 11 import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 12 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; 13 import org.springframework.beans.factory.annotation.Autowired; 14 import org.springframework.context.annotation.Bean; 15 import org.springframework.context.annotation.Configuration; 16 import org.springframework.context.annotation.DependsOn; 17 18 import com.SC.demo.realm.CustomRealm; 19 20 /** 21 * 描述: 22 * 23 * @author caojing 24 * @create 2019-01-27-13:38 25 */ 26 @Configuration 27 public class ShiroConfig { 28 29 // @Autowired 30 // CustomRealm customRealm; 31 32 @Bean(name = "shiroFilter") 33 public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { 34 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 35 shiroFilterFactoryBean.setSecurityManager(securityManager); 36 shiroFilterFactoryBean.setLoginUrl("/login"); 37 shiroFilterFactoryBean.setUnauthorizedUrl("/notRole"); 38 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); 39 // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> 40 filterChainDefinitionMap.put("/webjars/**", "anon"); 41 filterChainDefinitionMap.put("/login", "anon"); 42 filterChainDefinitionMap.put("/", "anon"); 43 filterChainDefinitionMap.put("/front/**", "anon"); 44 filterChainDefinitionMap.put("/api/**", "anon"); 45 46 filterChainDefinitionMap.put("/admin/**", "authc"); 47 filterChainDefinitionMap.put("/user/**", "authc"); 48 //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证 49 filterChainDefinitionMap.put("/**", "authc"); 50 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 51 return shiroFilterFactoryBean; 52 53 } 54 55 @Bean 56 public SecurityManager securityManager() { 57 DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); 58 defaultSecurityManager.setRealm(customRealm()); 59 return defaultSecurityManager; 60 } 61 62 @Bean 63 public CustomRealm customRealm() { 64 CustomRealm customRealm = new CustomRealm(); 65 // 告诉realm,使用credentialsMatcher加密算法类来验证密文 66 customRealm.setCredentialsMatcher(hashedCredentialsMatcher()); 67 customRealm.setCachingEnabled(false); 68 return customRealm; 69 } 70 71 72 @Bean 73 public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 74 return new LifecycleBeanPostProcessor(); 75 } 76 77 /** 78 * * 79 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 80 * * 81 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 82 * * @return 83 */ 84 @Bean 85 @DependsOn({"lifecycleBeanPostProcessor"}) 86 public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { 87 DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); 88 advisorAutoProxyCreator.setProxyTargetClass(true); 89 return advisorAutoProxyCreator; 90 } 91 92 @Bean 93 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { 94 AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); 95 authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); 96 return authorizationAttributeSourceAdvisor; 97 } 98 99 //shiro 加密配置 100 @Bean(name = "credentialsMatcher") 101 public HashedCredentialsMatcher hashedCredentialsMatcher() { 102 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); 103 // 散列算法:这里使用MD5算法; 104 hashedCredentialsMatcher.setHashAlgorithmName("md5"); 105 // 散列的次数,比如散列两次,相当于 md5(md5("")); 106 hashedCredentialsMatcher.setHashIterations(2); 107 // storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码 108 hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true); 109 return hashedCredentialsMatcher; 110 } 111 112 113 }
shiro的三个核心概念:
Subject: 代表当前正在执行操作的用户,但Subject代表的可以是人,也可以是任何第三方系统帐号。当然每个subject实例都会被绑定到SercurityManger上。
SecurityManger:SecurityManager是Shiro核心,主要协调Shiro内部的各种安全组件,这个我们不需要太关注,只需要知道可以设置自定的Realm。
Realm:用户数据和Shiro数据交互的桥梁。比如需要用户身份认证、权限认证。都是需要通过Realm来读取数据。
shiroFilter方法:
这个方法看名字就知道了:shiro的过滤器,可以设置登录页面(setLoginUrl)、权限不足跳转页面(setUnauthorizedUrl)、具体某些页面的权限控制或者身份认证。
注意:这里是需要设置SecurityManager(setSecurityManager)。
默认的过滤器还有:anno、authc、authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user过滤器。
具体的大家可以查看package org.apache.shiro.web.filter.mgt.DefaultFilter。这个类,常用的也就authc、anno。
securityManager 方法:
查看源码可以知道 securityManager是一个接口类,我们可以看下它的实现类:
具体怎么实现的,感兴趣的同学可以看下。由于项目是一个web项目,所以我们使用的是DefaultWebSecurityManager ,然后设置自己的Realm。
CustomRealm 方法:
将 customRealm的实例化交给spring去管理,当然这里也可以利用注解的方式去注入。
1 package com.SC.demo.realm; 2 3 import org.apache.shiro.SecurityUtils; 4 import org.apache.shiro.authc.*; 5 import org.apache.shiro.authz.AuthorizationInfo; 6 import org.apache.shiro.authz.SimpleAuthorizationInfo; 7 import org.apache.shiro.realm.AuthorizingRealm; 8 import org.apache.shiro.subject.PrincipalCollection; 9 import org.apache.shiro.subject.Subject; 10 import org.apache.shiro.util.ByteSource; 11 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.context.annotation.Bean; 13 import org.springframework.context.annotation.Configuration; 14 import org.springframework.stereotype.Component; 15 16 import com.SC.demo.pojo.Sys_Roles; 17 import com.SC.demo.pojo.Sys_Users; 18 import com.SC.demo.pojo.Sys_permissions; 19 import com.SC.demo.service.serviceimp.UserServiceImp; 20 21 import java.util.HashSet; 22 import java.util.Set; 23 24 /** 25 * @author 作者 :Runaway programmer 26 * @version 创建时间:2019年12月18日 下午4:48:28 27 * 类说明 28 */ 29 30 public class CustomRealm extends AuthorizingRealm { 31 32 @Autowired 33 UserServiceImp userServiceImp; 34 35 @Override 36 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 37 String username = (String) SecurityUtils.getSubject().getPrincipal(); 38 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 39 //从数据库中获取当前用户拥有的权限 存入集合中 再存入SimpleAuthorizationInfo对象里供注解获取对比权限 40 Sys_permissions permission = userServiceImp.getUserRole(username); 41 Set<String> stringSet = new HashSet<>(); 42 stringSet.add(permission.getPermission()); 43 stringSet.add("user:admin"); 44 info.setStringPermissions(stringSet); 45 return info; 46 } 47 48 /** 49 * 这里可以注入userService,为了方便演示,我就写死了帐号了密码 50 * private UserService userService; 51 * <p> 52 * 获取即将需要认证的信息 53 */ 54 @Override 55 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { 56 System.out.println("-------身份认证方法--------"); 57 String userName = (String) authenticationToken.getPrincipal(); 58 System.out.println(userName); 59 String userPwd = new String((char[]) authenticationToken.getCredentials()); 60 61 //根据用户名从数据库获取密码 62 Sys_Users userNamePassword = userServiceImp.getUserNamePassword(userName); 63 String password = userNamePassword.getPassword(); 64 String salt = userNamePassword.getSalt(); 65 // String password = "4b91fc877a3f4df7e812f98ebde4b5e5"; 66 if (userName == null) { 67 throw new AccountException("用户名不正确"); 68 } else if (!userPwd.equals(userPwd)) { 69 throw new AccountException("密码不正确"); 70 } 71 //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配 72 //1.当前用户名userName 2.以及数据库查询password 3.盐 (设置的盐 userName+Salt)4.当前realm对象 73 return new SimpleAuthenticationInfo(userName, password, 74 ByteSource.Util.bytes(userName + salt), getName()); 75 76 } 77 }
说明:
自定义的Realm类继承AuthorizingRealm类,并且重载doGetAuthorizationInfo和doGetAuthenticationInfo两个方法。
doGetAuthorizationInfo: 权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。
doGetAuthenticationInfo:身份认证。即登录通过账号和密码验证登陆人的身份信息。
controller类:
1 package com.SC.demo.controller; 2 3 import org.apache.shiro.SecurityUtils; 4 import org.apache.shiro.authc.AuthenticationException; 5 import org.apache.shiro.authc.ExcessiveAttemptsException; 6 import org.apache.shiro.authc.IncorrectCredentialsException; 7 import org.apache.shiro.authc.LockedAccountException; 8 import org.apache.shiro.authc.UnknownAccountException; 9 import org.apache.shiro.authc.UsernamePasswordToken; 10 import org.apache.shiro.subject.Subject; 11 import org.springframework.web.bind.annotation.RequestMapping; 12 import org.springframework.web.bind.annotation.RequestMethod; 13 import org.springframework.web.bind.annotation.RequestParam; 14 import org.springframework.web.bind.annotation.ResponseBody; 15 import org.springframework.web.bind.annotation.RestController; 16 17 import com.SC.demo.utils.MD5utils; 18 19 /** 20 * @author 作者 :Runaway programmer 21 * @version 创建时间:2019年12月18日 下午4:49:50 22 * 类说明 23 */ 24 @RestController 25 public class HomeIndexController { 26 27 @RequestMapping(value = "/login", method = RequestMethod.GET) 28 @ResponseBody 29 public String defaultLogin() { 30 return "首页"; 31 } 32 33 @RequestMapping(value = "/login", method = RequestMethod.POST) 34 @ResponseBody 35 public String login(@RequestParam("username") String username, @RequestParam("password") String password) { 36 // 从SecurityUtils里边创建一个 subject 37 Subject subject = SecurityUtils.getSubject(); 38 // 在认证提交前准备 token(令牌) 39 UsernamePasswordToken token = new UsernamePasswordToken(username, password); 40 //MD5加盐获取值 41 String md5Pwd = MD5utils.MD5Pwd(username, password); 42 System.out.println(md5Pwd); 43 // 执行认证登陆 44 try { 45 subject.login(token); 46 } catch (UnknownAccountException uae) { 47 return "未知账户"; 48 } catch (IncorrectCredentialsException ice) { 49 return "密码不正确"; 50 } catch (LockedAccountException lae) { 51 return "账户已锁定"; 52 } catch (ExcessiveAttemptsException eae) { 53 return "用户名或密码错误次数过多"; 54 } catch (AuthenticationException ae) { 55 return "用户名或密码不正确!"; 56 } 57 if (subject.isAuthenticated()) { 58 return "登录成功"; 59 } else { 60 token.clear(); 61 return "登录失败"; 62 } 63 } 64 65 }
利用注解配置权限:
其实,我们完全可以不用注解的形式去配置权限,因为在之前已经加过了:DefaultFilter类中有perms(类似于perms[user:add])这种形式的。但是试想一下,这种控制的粒度可能会很细,具体到某一个类中的方法,那么如果是配置文件配,是不是每个方法都要加一个perms?但是注解就不一样了,直接写在方法上面,简单快捷。
很简单,主需要在config类中加入如下代码,就能开启注解:
1 @Bean 2 public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 3 return new LifecycleBeanPostProcessor(); 4 } 5 6 /** 7 * * 8 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 9 * * 10 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 11 * * @return 12 */ 13 @Bean 14 @DependsOn({"lifecycleBeanPostProcessor"}) 15 public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { 16 DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); 17 advisorAutoProxyCreator.setProxyTargetClass(true); 18 return advisorAutoProxyCreator; 19 } 20 21 @Bean 22 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { 23 AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); 24 authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); 25 return authorizationAttributeSourceAdvisor; 26 } 27 28 //shiro 加密配置 29 @Bean(name = "credentialsMatcher") 30 public HashedCredentialsMatcher hashedCredentialsMatcher() { 31 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); 32 // 散列算法:这里使用MD5算法; 33 hashedCredentialsMatcher.setHashAlgorithmName("md5"); 34 // 散列的次数,比如散列两次,相当于 md5(md5("")); 35 hashedCredentialsMatcher.setHashIterations(2); 36 // storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码 37 hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true); 38 return hashedCredentialsMatcher; 39 }
注解权限Controller测试类
1 package com.SC.demo.controller; 2 3 import org.apache.shiro.authz.annotation.RequiresPermissions; 4 import org.apache.shiro.authz.annotation.RequiresRoles; 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 import org.springframework.web.bind.annotation.ResponseBody; 8 9 /** 10 * @author 作者 :Runaway programmer 11 * @version 创建时间:2019年12月18日 下午5:08:27 12 * 类说明 13 */ 14 15 @RequestMapping("/user") 16 @Controller 17 public class UserController { 18 @RequiresPermissions("user:admin") 19 @ResponseBody 20 @RequestMapping("/show") 21 public String showUser() { 22 return "这是学生信息"; 23 } 24 25 @RequiresPermissions("user:create") 26 // @RequiresRoles("") 27 @ResponseBody 28 @RequestMapping("/test") 29 public String testData() { 30 return "这是测试Shiro 权限拦截情况"; 31 32 } 33 }
密码采用加密方式进行验证:
其实上面的功能已经基本满足我们的需求了,但是唯一一点美中不足的是,密码都是采用的明文方式进行比对的。那么shiro是否提供给我们一种密码加密的方式呢?答案是肯定。
shiroConfig中加入加密配置:
1 //shiro 加密配置 2 @Bean(name = "credentialsMatcher") 3 public HashedCredentialsMatcher hashedCredentialsMatcher() { 4 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); 5 // 散列算法:这里使用MD5算法; 6 hashedCredentialsMatcher.setHashAlgorithmName("md5"); 7 // 散列的次数,比如散列两次,相当于 md5(md5("")); 8 hashedCredentialsMatcher.setHashIterations(2); 9 // storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码 10 hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true); 11 return hashedCredentialsMatcher; 12 }
customRealm初始化的时候耶需要做一些改变:
1 @Bean 2 public CustomRealm customRealm() { 3 CustomRealm customRealm = new CustomRealm(); 4 // 告诉realm,使用credentialsMatcher加密算法类来验证密文 5 customRealm.setCredentialsMatcher(hashedCredentialsMatcher()); 6 customRealm.setCachingEnabled(false); 7 return customRealm; 8 }
流程是这样的,用户注册的时候,程序将明文通过加密方式加密,存到数据库的是密文,登录时将密文取出来,再通过shiro将用户输入的密码进行加密对比,一样则成功,不一样则失败。
我们可以看到这里的加密采用的是MD5,而且是加密两次(MD5(MD5))。
shiro提供了SimpleHash类帮助我们快速加密:
1 package com.SC.demo.utils; 2 3 import org.apache.shiro.crypto.hash.SimpleHash; 4 import org.apache.shiro.util.ByteSource; 5 6 /** 7 * @author 作者 :Runaway programmer 8 * @version 创建时间:2019年12月19日 上午8:48:47 9 * 类说明 10 */ 11 12 public class MD5utils { 13 14 public static String MD5Pwd(String username, String pwd) { 15 // 加密算法MD5 16 // salt盐 username + salt 17 // 迭代次数 18 String md5Pwd = new SimpleHash("MD5", pwd, 19 ByteSource.Util.bytes(username + "salt"), 2).toHex(); 20 return md5Pwd; 21 } 22 23 24 }
也就是说注册的时候调用一下上面的方法得到密文之后,再存入数据库。
在CustomRealm进行身份认证的时候我们也需要作出改变:
1 System.out.println("-------身份认证方法--------"); 2 String userName = (String) authenticationToken.getPrincipal(); 3 String userPwd = new String((char[]) authenticationToken.getCredentials()); 4 //根据用户名从数据库获取密码 5 String password = "2415b95d3203ac901e287b76fcef640b"; 6 if (userName == null) { 7 throw new AccountException("用户名不正确"); 8 } else if (!userPwd.equals(userPwd)) { 9 throw new AccountException("密码不正确"); 10 } 11 //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配 12 return new SimpleAuthenticationInfo(userName, password, 13 ByteSource.Util.bytes(userName + "salt"), getName());