1:引入spring-shiro 依赖
<!--权限拦截-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
2:配置shiro的生命周期和切面拦截
@Configuration
@Slf4j
public class ShiroHelperConfig {
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
log.info("lifecycleBeanPostProcessor bean");
return new LifecycleBeanPostProcessor();
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
log.info("lifecycleBeanPostProcessor bean");
return creator;
}
}
3:配置shiro的安全管理器
/**
* shiro configuration
**/
@Configuration
@Slf4j
@AutoConfigureAfter(value = {ShiroHelperConfig.class})
public class ShiroConfig {
@Bean(name = "securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") TourismAuthorizingRealm authRealm,
@Qualifier("cookieRememberMeManager") CookieRememberMeManager cookieRememberMeManager) {
log.info("securityManager()");
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置rememberMe管理器
securityManager.setRememberMeManager(cookieRememberMeManager);
// 设置realm,解决doGetAuthorizationInfo方法没有调用问题
securityManager.setRealm(authRealm);
return securityManager;
}
/**
* realm
*
* @return
*/
@Bean(name = "authRealm")
public TourismAuthorizingRealm tourismAuthorizingRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
log.info("tourismAuthorizingRealm bean");
TourismAuthorizingRealm myAuthorizingRealm = new TourismAuthorizingRealm();
// 设置密码凭证匹配器
myAuthorizingRealm.setCredentialsMatcher(matcher);
return myAuthorizingRealm;
}
/**
* cookie对象;
*
* @return
*/
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//记住我cookie生效时间30天(259200)单位秒;
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* 记住我管理器 cookie管理对象;
*/
@Bean(name = "cookieRememberMeManager")
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
/**
* 密码匹配凭证管理器
*
* @return
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName(PasswordUtils.ALGORITHM_NAME);
hashedCredentialsMatcher.setHashIterations(PasswordUtils.HASH_ITERATIONS);// 散列的次数,比如散列两次,相当于
return hashedCredentialsMatcher;
}
/**
* 开启shiro aop注解支持.
* <p>
* 使用代理方式;所以需要开启代码支持;
* Controller才能使用@RequiresPermissions
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
@Qualifier("securityManager") SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
4:配置shiro的校验器
public class TourismAuthorizingRealm extends AuthorizingRealm {
private final static Logger logger = LoggerFactory.getLogger(TourismAuthorizingRealm.class);
@Autowired
@Qualifier("userService")
private UserService userService;
//shiro的权限配置方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("权限配置-->doGetAuthorizationInfo");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
logger.info("----------------------------->" + principals.getPrimaryPrincipal());
User user = (User) principals.getPrimaryPrincipal();
logger.info("doGetAuthorizationInfo() user: {}", user);
List<Role> roles = userService.getRoles(user.getUserId());
for (Role role : roles) {
authorizationInfo.addRole(role.getRoleName());
// 如果有权限,应该增加所有角色对应的权限
// authorizationInfo.addStringPermission()
}
logger.info("用户: {},具有的角色: {}", user.getUserName(), authorizationInfo.getRoles());
logger.info("用户: {},具有的权限: {}", user.getUserName(), authorizationInfo.getStringPermissions());
return authorizationInfo;
}
//shiro的身份验证方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
logger.info("正在验证身份...");
SimpleAuthenticationInfo info = null;
//将token转换成UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//从转换后的token中获取用户名
String username = upToken.getUsername();
//查询数据库,得到用户
User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUserName, username));
if (user == null) {
logger.info("没有用户: {}", username);
return null;
}
//得到加密密码的盐值
ByteSource salt = ByteSource.Util.bytes(user.getUserSalt());
logger.info("加密密码的盐: {}", salt);
//得到盐值加密后的密码: 只用于方便数据库测试,后期不会用到。
Object md = new SimpleHash(PasswordUtils.ALGORITHM_NAME, upToken.getPassword(), salt, PasswordUtils.HASH_ITERATIONS);
logger.info("盐值加密后的密码: {}", md);
//TODO: 用户名;用户密码;加密盐;realm name
info = new SimpleAuthenticationInfo(user, user.getUserPassword(), salt, getName());
return info;
}
5:配置用户的加密方式
/**
* password utils
**/
public class PasswordUtils {
public static final String ALGORITHM_NAME = "MD5";
public static final int HASH_ITERATIONS = 1024;
/**
* 重新计算md5值
*
* @param password
* @param salt
* @return
*/
public static String renewPassword(String password, String salt) {
SimpleHash md5hash = new SimpleHash(
ALGORITHM_NAME, password, salt, HASH_ITERATIONS);
return md5hash.toHex();
}
}