shiro 登录
/**
* 登录
* @param userName
* @param password
* @return
*/
@RequestMapping(value = "/login",method = RequestMethod.POST)
public Result login(String userName, String password) {
System.out.println("---------------------------------------"+userName+userName);
Result result = new Result();
Subject user = SecurityUtils.getSubject();
//获取随机成为的唯一认证
Session session = user.getSession();
//登陆校验
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
try {
user.login(token);
//自定义的对象(主要用于存储想要的登录信息)
ShiroAccount shiroAccount = (ShiroAccount) user.getPrincipal();
if (user.isAuthenticated()) { // 验证身份通过
//常量,用于存储需要的数据
session.setAttribute("userLogin", user.getPrincipal());
}
// 给用户jwt加密生成token
// String jwtToken = JwtUtil.sign(shiroAccount, 60L* 1000L* 30L);
String jwtToken = session.getId().toString();
result.setData(shiroAccount);
result.setSuccess(true);
result.setToken(jwtToken);
result.setMsg("登录成功");
} catch (UnknownAccountException e) {
// throw new RuntimeException("账号不存在!", e);
result.setSuccess(false);
result.setMsg("账号不存在!");
} catch (DisabledAccountException e) {
// throw new RuntimeException("账号未启用!", e);
result.setSuccess(false);
result.setMsg("账号未启用!");
} catch (IncorrectCredentialsException e) {
// throw new RuntimeException("密码错误!", e);
result.setSuccess(false);
result.setMsg("密码错误!");
} catch (Throwable e) {
// throw new RuntimeException(e.getMessage(), e);
result.setSuccess(false);
result.setMsg(e.getMessage());
}
return result;
}
/**
* 退出登录
* @param userName
* @param password
* @return
*/
@RequestMapping(method = RequestMethod.POST, value="logout")
public Result logout(HttpSession session) {
Result result =new Result();
Subject subject = SecurityUtils.getSubject();
subject.logout();
result.setData("");
result.setSuccess(true);
return result;
}
退出和登录主要涉及到的是:Shiro的Subject对象详解:
登录的认证步骤:
package com.fcar.kj.manager.shiro;
import com.fcar.kj.common.entities.ShiroAccount;
import com.fcar.kj.common.entities.account.SysAccount;
import com.fcar.kj.common.entities.account.SysRole;
import com.fcar.kj.manager.bsj.service.RoleService;
import com.fcar.kj.manager.service.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ByteSource;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
/**
* shiroRealm配置
*
* @date 2020/7/16 20:35
*/
@Slf4j
public class UserRealm extends AuthorizingRealm {
@Autowired
private AccountService accountService;
@Autowired
private RedisSessionDAO redisSessionDAO;
@Autowired
private RoleService roleService;
public UserRealm() {
super();
}
/**
* 授权(权限)
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
ShiroAccount shiroAccount = (ShiroAccount) principals.getPrimaryPrincipal();
Integer id = shiroAccount.getId();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// TODO 加个批量方法
// Set roles = accountService.findRoles(id);
// Set permissions = accountService.findPermissions(id);
Set<String> roleSet = accountService.findRolesSetByUserId(id);
if (roleSet.isEmpty()) {
authorizationInfo.setRoles(roleSet);
authorizationInfo.setStringPermissions(new HashSet<>());
return authorizationInfo;
}
Set<String> permissions = accountService.findPermissionSetByUserId(id);
authorizationInfo.setRoles(roleSet);
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
/**
* 认证(登录认证)
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
Object password = token.getCredentials();
if (username == null || username.length() == 0 || password == null) {
throw new IncorrectCredentialsException();//用户名、密码为空
}
SysAccount account = accountService.findByUsername(username);
if (account == null) {
throw new UnknownAccountException();//没找到帐号
}
if (account.getLocked() == 1) {
throw new LockedAccountException(); //帐号锁定
}
Integer userId = account.getUserid();
//保存登录的参数
ShiroAccount shiroUser = new ShiroAccount(userId, account.getUsername());
shiroUser.setOrganizationid(account.getOrganizationid());
// TODO 根据用户id查询角色信息
List<SysRole> sysRoleList = accountService.findRoleListByUserId(userId);
if (sysRoleList.isEmpty()){
throw new LockedAccountException(); //帐号锁定
}
shiroUser.setSysRoleList(sysRoleList);
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现。参数:用户名、密码、salt=username+salt、realm name
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(shiroUser, account.getPassword(),
ByteSource.Util.bytes(account.getCredentialsSalt()), getName());
return authenticationInfo;
}
/**
* 清除认证信息(修改密码)
*
* @param userIds
*/
public void clearCachedAuthenticationInfoByUserId(List<Integer> userIds) {
if (null == userIds || userIds.size() == 0) {
return;
}
List<SimplePrincipalCollection> list = getSpcListByUserIds(userIds);
RealmSecurityManager securityManager =
(RealmSecurityManager) SecurityUtils.getSecurityManager();
UserRealm realm = (UserRealm) securityManager.getRealms().iterator().next();
for (SimplePrincipalCollection simplePrincipalCollection : list) {
realm.clearCachedAuthenticationInfo(simplePrincipalCollection);
}
}
/**
* 根据userId 清除当前session存在的用户的权限缓存(修改角色权限)
*
* @param userIdList 已经修改了权限的userId
*/
public void clearAuthorizationByUserId(List<Integer> userIdList) {
if (null == userIdList || userIdList.size() == 0) {
return;
}
List<SimplePrincipalCollection> list = getSpcListByUserIds(userIdList);
RealmSecurityManager securityManager =
(RealmSecurityManager) SecurityUtils.getSecurityManager();
UserRealm realm = (UserRealm) securityManager.getRealms().iterator().next();
for (SimplePrincipalCollection simplePrincipalCollection : list) {
realm.clearCachedAuthorizationInfo(simplePrincipalCollection);
}
}
/**
* 根据用户id获取所有spc
*
* @param userIdList 已经修改了权限的userId
*/
private List<SimplePrincipalCollection> getSpcListByUserIds(List<Integer> userIdList) {
//获取所有session
Collection<Session> sessions = redisSessionDAO.getActiveSessions();
//定义返回
List<SimplePrincipalCollection> list = new ArrayList<>();
for (Session session : sessions) {
//获取session登录信息。
Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (null != obj && obj instanceof SimplePrincipalCollection) {
//强转
SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
//判断用户,匹配用户ID。
obj = spc.getPrimaryPrincipal();
if (null != obj && obj instanceof ShiroAccount) {
ShiroAccount user = (ShiroAccount) obj;
log.info("重置的user:" + user);
//比较用户ID,符合即加入集合
if (null != user && userIdList.contains(user.getId())) {
list.add(spc);
}
}
}
}
return list;
}
}
登录校验:
@Slf4j
public class MySessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "Authorization";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public MySessionManager() {
super();
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if(StringUtils.isEmpty(id)){
id = request.getParameter(AUTHORIZATION);
}
//如果请求头中有 Authorization 则其值为sessionId
if (!StringUtils.isEmpty(id)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
} else {
//否则按默认规则从cookie取sessionId 可以防止XSS攻击
Serializable sessionId = super.getSessionId(request, response);
log.info("sessionId={}",sessionId);
return sessionId;
}
}
}
获取登录信息:
package com.fcar.kj.manager.utils;
import com.fcar.kj.bsj.common.constant.CoreConstant;
import com.fcar.kj.common.entities.ShiroAccount;
import org.apache.shiro.SecurityUtils;
/**
* 获取用户id
*
* @author 李晨亮
* @date 2020-07-09 15:51
**/
public class UserUtil {
/**
* 获取登录用户id
*
* @return
*/
public static int getUserId() {
ShiroAccount shiroAccount = getShiroAccount();
int userId = shiroAccount.getId();
return userId;
}
/**
* 查询用户数据权限
*
* @return
*/
public static int getDataScopeType() {
ShiroAccount shiroAccount = getShiroAccount();
Integer dataScopeType = shiroAccount.getSysRoleList().get(0).getDataScopeType();
return dataScopeType == null ? 0 : dataScopeType;
}
/**
* 获取机构id
*
* @return
*/
public static int getOrgId() {
ShiroAccount shiroAccount = getShiroAccount();
return shiroAccount.getOrganizationid();
}
/**
* 获取登录用户信息
*
* @return
*/
public static ShiroAccount getShiroAccount() {
return (ShiroAccount) SecurityUtils.getSubject().getSession().getAttribute("userLogin");
}
}
初始化Shiro的缓存机制:
package com.fcar.kj.manager.config;
import com.auth0.jwt.internal.org.apache.commons.lang3.StringUtils;
import com.fcar.kj.bsj.common.constant.CoreConstant;
import com.fcar.kj.bsj.common.utils.StringUtil;
import com.fcar.kj.common.entities.account.SysResource;
import com.fcar.kj.manager.dao.bsj.SysResourceDao;
import com.fcar.kj.manager.shiro.MySessionManager;
import com.fcar.kj.manager.shiro.UserRealm;
import com.fcar.kj.manager.shiro.filter.CustomFormAuthenticationFilter;
import com.fcar.kj.manager.shiro.filter.CustomPermissionsAuthorizationFilter;
import com.fcar.kj.manager.utils.MyExceptionHandler;
import com.fcar.kj.manager.utils.WebHashedCredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
// @Value("${spring.redis.timeout}")
// private int timeout;
@Value("${spring.redis.password}")
private String password;
@Resource
private SysResourceDao sysResourceDao;
//这里是初时话Shiro拦截的过滤机制
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置自定义的过滤器, 配置过滤器,跨域访问时,对OPTIONS的请求返回true,这个很重要,不然不能获取header上的值
Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
filters.put("authc", new CustomFormAuthenticationFilter());
filters.put("perms", new CustomPermissionsAuthorizationFilter());
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//注意过滤器配置顺序 不能颠倒
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
//anon: 无需认证即可访问
//authc: 需要认证才可访问
//user: 点击“记住我”功能可访问
//perms: 拥有权限才可以访问
//role: 拥有某个角色权限才能访问
filterChainDefinitionMap.put("/user/logout", "logout");
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/user/ajaxLogin", "anon");
filterChainDefinitionMap.put("/user/login", "anon");
//pdf授权访问路径对外打开
filterChainDefinitionMap.put("/fession/ossauth", "anon");
// 上传图片和视频
filterChainDefinitionMap.put("/ueditor/getConfig", "anon");
filterChainDefinitionMap.put("/article/getUploadImgUrl", "anon");
filterChainDefinitionMap.put("/article/getUploadAdviceUrl", "anon");
// 查询数据库权限配置
List<SysResource> resourceList = sysResourceDao.selectAllResource(CoreConstant.AVAILABLE_NORMAL);
for (SysResource sysResource : resourceList) {
String path = sysResource.getPath();
String permission = sysResource.getPermission();
if (StringUtils.isNotBlank(path) && StringUtils.isNotBlank(permission)) {
String perm = "perms[" + permission + "]";
filterChainDefinitionMap.put(path, perm);
}
}
filterChainDefinitionMap.put("/**", "authc");
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
shiroFilterFactoryBean.setLoginUrl("/user/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* )
*
* @return
*/
@Bean("name = webHashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
// HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
// hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
// return hashedCredentialsMatcher;
return new WebHashedCredentialsMatcher();
}
//已下就是初始化UserRealm登录存储额缓存机制(这里使用redis作为缓存工具)
@Bean
public UserRealm myShiroRealm() {
UserRealm myShiroRealm = new UserRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
// 自定义session管理 使用redis
securityManager.setSessionManager(sessionManager());
// 自定义缓存实现 使用redis
securityManager.setCacheManager(cacheManager());
return securityManager;
}
//自定义sessionManager
@Bean
public SessionManager sessionManager() {
MySessionManager mySessionManager = new MySessionManager();
mySessionManager.setSessionDAO(redisSessionDAO());
mySessionManager.setGlobalSessionTimeout(43200000);//12小时
return mySessionManager;
}
/**
* 配置shiro redisManager
*
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host + ":" + port);
// redisManager.setExpire(1800);// 配置缓存过期时间
// redisManager.setTimeout(timeout);
redisManager.setPassword(password);
return redisManager;
}
/**
* cacheManager 缓存 redis实现
*
* 使用的是shiro-redis开源插件
*
* @return
*/
@Bean
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
*
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 注册全局异常处理
*
* @return
*/
@Bean(name = "exceptionHandler")
public HandlerExceptionResolver handlerExceptionResolver() {
return new MyExceptionHandler();
}
}
这里是拦截器的过滤机制顺便解决了跨域问题(这里没有解决到权限访问的问题):
package com.fcar.kj.manager.shiro.filter;
import com.alibaba.fastjson.JSONObject;
import com.fcar.kj.common.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 自定义权限过滤器
*
* @date 2020-07-24 15:05
**/
public class CustomPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter {
/**
* 屏蔽OPTIONS请求
*
* @param request
* @param response
* @param mappedValue
* @return
* @throws IOException
*/
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
// 判断请求是否是options请求
String method = WebUtils.toHttp(request).getMethod();
if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
return true;
}
return super.isAccessAllowed(request, response, mappedValue);
}
/**
* 解决权限不足302问题
*
* @param request
* @param response
* @return
* @throws IOException
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = getSubject(request, response);
if (subject.getPrincipal() == null) {
saveRequestAndRedirectToLogin(request, response);
} else {
WebUtils.toHttp(response).setContentType("application/json; charset=utf-8");
WebUtils.toHttp(response).getWriter().print(JSONObject.toJSONString(new Result<>().fali("无权限")));
}
return false;
}
}
package com.fcar.kj.manager.shiro.filter;
import com.alibaba.fastjson.JSONObject;
import com.fcar.kj.common.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 自定义认证过滤器
*
* @date 2020/7/24 15:54
*/
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {
/**
* 屏蔽OPTIONS请求
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
boolean accessAllowed = super.isAccessAllowed(request, response, mappedValue);
if (!accessAllowed) {
// 判断请求是否是options请求
String method = WebUtils.toHttp(request).getMethod();
if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
return true;
}
}
return super.isAccessAllowed(request, response, mappedValue);
}
/**
* 解决未登录302问题
*
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
return executeLogin(request, response);
} else {
return true;
}
} else {
// 返回固定的JSON串
WebUtils.toHttp(response).setContentType("application/json; charset=utf-8");
WebUtils.toHttp(response).getWriter().print(JSONObject.toJSONString(new Result<>().fali("未登录")));
return false;
}
}
}
自定义角色权限过滤:
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @Date: 2019/4/18 0018 17:40
* @Description:支持多角色验证
* 由于Shiro filterChainDefinitions中 roles默认是and,
* = user,roles[system,general]
* 比如:roles[system,general] ,表示同时需要“system”和“general” 2个角色才通过认证
* 但是在实际业务中,一个端口的权限往往对多个角色开放(比如管理员可以使用一切权利)
*/
public class MyRolesAuthorizationFilter extends AuthorizationFilter{
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
Subject subject = getSubject(request, response);
String[] rolesArray = (String[]) mappedValue;
//没有权限访问
if (rolesArray == null || rolesArray.length == 0) {
return true;
}
for (int i = 0; i < rolesArray.length; i++) {
//若当前用户是rolesArray中的任何一个,则有权限访问
if (subject.hasRole(rolesArray[i])) {
return true;
}
}
return false;
}
}
在ShiroConfig引用,其实spring boot集成shiro也就这两步,加上自定义权限验证 和自定义登录验证。
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {
//System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加自定义验证方法,注意这个Filter继承javax.servlet.Filter
Map<String, Filter> filterMap=new HashMap<>();
filterMap.put("rolesOr",roleFilter());
shiroFilterFactoryBean.setFilters(filterMap);
//拦截器.
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/gif/**", "anon");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/sanyi/logout", "logout");
//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
//
filterChainDefinitionMap.put("/sanyi/index", "anon");/*swagger*/
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
/*business业务端(1管理员,3业务员)*/
filterChainDefinitionMap.put("/contract/base/**", "authc,rolesOr[1,3]");
/*其他,一定要采取白名单*/
filterChainDefinitionMap.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
shiroFilterFactoryBean.setLoginUrl("/sanyi/index");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/sanyi/nopermission");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public MyRolesAuthorizationFilter roleFilter(){
MyRolesAuthorizationFilter roleFilter=new MyRolesAuthorizationFilter();
return roleFilter;
}
/**
* 密码凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* )
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(10);//散列的次数10哈哈;
return hashedCredentialsMatcher;
}
/**
* 身份认证realm; (这个需要自己写,账号密码校验;权限等)
* @return
*/
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
/**
* 会话管理器
* @return
*/
@Bean
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1800000);//单位是ms
return sessionManager;
}
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
securityManager.setSessionManager(sessionManager());
return securityManager;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException","403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("exception"); // Default is "exception"
//r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}
}