一、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.setPassword(redisPassword);
redisManager.setExpire(Integer.valueOf(reidsExpire));// 配置缓存过期时间
redisManager.setTimeout(Integer.valueOf(redisTimeout));
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";
}
}
}