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();
}
}