Shiro+Redis Session共享
阿新 • • 發佈:2018-12-19
一、pom匯入包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>2.4.2.1-RELEASE</version> </dependency>
二、配置
1、config
package com.cfl.account.admin.config; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; import javax.servlet.Filter; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisManager; import org.crazycake.shiro.RedisSessionDAO; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; @Configuration @PropertySource(value={"classpath:config.properties"}) public class ShiroConfiguration { @Value("${redis_url}") private String redisUrl; @Value("${redis_port}") private String redisPort; @Value("${redis_password}") private String redisPassword; @Value("${reids_expire}") private String reidsExpire; @Value("${redis_timeout}") private String redisTimeout; @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 沒有登陸的使用者只能訪問登陸頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登入成功後要跳轉的連結 shiroFilterFactoryBean.setSuccessUrl("/home"); //自定義攔截器 Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>(); shiroFilterFactoryBean.setFilters(filtersMap); // 許可權控制map. Map<String, String> map = new LinkedHashMap<String, String>(); map.put("/login", "anon"); map.put("/role_error", "anon"); map.put("/static/**", "anon"); map.put("/admin/**", "roles"); map.put("/login/outLogin", "logout"); // 退出 shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設定realm. securityManager.setRealm(myShiroRealm()); // 自定義快取實現 使用redis securityManager.setCacheManager(cacheManager()); // 自定義session管理 使用redis securityManager.setSessionManager(sessionManager()); return securityManager; } /** * 身份認證realm; (這個需要自己寫,賬號密碼校驗;許可權等) * * @return */ @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } /** * cacheManager 快取 redis實現 * 使用的是shiro-redis開源外掛 * * @return */ public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * 配置shiro redisManager * 使用的是shiro-redis開源外掛 * * @return */ public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(redisUrl); redisManager.setPort(Integer.valueOf(redisPort)); redisManager.setExpire(Integer.valueOf(reidsExpire));// 配置快取過期時間 redisManager.setTimeout(Integer.valueOf(redisTimeout)); // redisManager.setPassword(password); return redisManager; } /** * Session Manager * 使用的是shiro-redis開源外掛 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; } /** * RedisSessionDAO shiro sessionDao層的實現 通過redis * 使用的是shiro-redis開源外掛 */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } /*** * 使授權註解起作用不如不想配置可以在pom檔案中加入 * <dependency> *<groupId>org.springframework.boot</groupId> *<artifactId>spring-boot-starter-aop</artifactId> *</dependency> * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * Shiro生命週期處理器,必須加static,不然獲取不到spring裡面的東西,比如@Value註解 * */ @Bean public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /*** * 授權所用配置 * * @return */ @Bean public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); return defaultAdvisorAutoProxyCreator; } @Bean public static SimpleMappingExceptionResolver resolver() { SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties properties = new Properties(); properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/role_error"); resolver.setExceptionMappings(properties); return resolver; } }
2、認證
package com.cfl.account.admin.config; import java.util.HashSet; import java.util.Set; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.stereotype.Component; import com.alibaba.dubbo.config.annotation.Reference; import com.cfl.account.commons.result.APIResultDO; import com.cfl.account.commons.result.ResultDO; import com.cfl.account.interfaces.user.facade.UserFacade; import com.cfl.account.model.vo.RoleVo; import com.cfl.account.model.vo.UserVo; @Component public class MyShiroRealm extends AuthorizingRealm { @Reference private UserFacade userFacade; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Set<String> roleSet = new HashSet<String>(); // 角色 // Set<String> permissionSet = new HashSet<String>(); // 許可權 ResultDO<RoleVo> resultDO = userFacade.findUserRoleByName(principals.toString()); if(APIResultDO.CODE_SUCCESS == resultDO.getResultCode()) { // 登入成功 RoleVo roleVo = resultDO.getModule(); if(roleVo != null) { roleSet.add(roleVo.getName()); } } SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // simpleAuthorizationInfo.setStringPermissions(permissionSet); simpleAuthorizationInfo.setRoles(roleSet); return simpleAuthorizationInfo; } /** * 使用者認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String name = token.getUsername(); String password = new String((char[]) token.getCredentials()); ResultDO<UserVo> resultDO = userFacade.login(name, password); if (APIResultDO.CODE_SUCCESS == resultDO.getResultCode()) { // 登入成功 return new SimpleAuthenticationInfo(token.getPrincipal(), password, getName()); } else { throw new AuthenticationException(resultDO.getErrorMesssage()); } } }
3、解決使用註解RequiresRoles攔截頁面無法調整的問題
package com.cfl.account.admin.config;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class MyControllerAdvice {
/**
* 全域性異常捕捉處理,當shiro碰到AuthorizationException時進入到無許可權頁面或登入頁面 解決使用@RequiresRoles註解時bug
* @param
* @return
*/
@ExceptionHandler(value = AuthorizationException.class)
public Object errorHandler(AuthorizationException ex) {
if(ex.getMessage().indexOf("Subject does not have role") != -1) {
// 無許可權頁面
return "/role_error";
} else {
// 登入頁面
return "redirect:/login";
}
}
}