本文主要是为让大家快速上手整合Shiro进入项目,完成拦截,认证,授权等功能,具体的原理可能并不会过多的描述请大家谅解 。
什么是ShiroShiro是一个功能强大且易于使用的Java安全框架,它执行身份验证、授权、加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序—从最小的移动应用程序到最大的web和企业应用程序。
依赖
org.apache.shiro
shiro-spring-boot-starter
${shiro.version}
nz.net.ultraq.thymeleaf
thymeleaf-layout-dialect
${thymeleaf-layout-dialect.version}
com.github.theborakompanioni
thymeleaf-extras-shiro
${thymeleaf-extras-shiro.version}
Shiro使用自定义Relam实现认证授权
@Slf4j
public class JwtRealm extends AuthorizingRealm {
@Resource
private JwtTokenUtil jwtTokenUtil;
@DubboReference
private ISysUserService userService;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.info("===============Shiro权限认证开始============ [ roles、permissions]==========");
Long userId = null;
String loginName = null;
if (null != principalCollection) {
LoginUserVo loginUserVoVo = (LoginUserVo) principalCollection.getPrimaryPrincipal();
userId = loginUserVoVo.getId();
loginName = loginUserVoVo.getLoginName();
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//TODO: 设置用户拥有的角色集合
Set roleSet = userService.selectUserRoles(userId);
info.setRoles(roleSet);
//TODO: 设置用户拥有的权限集合
Set permissionSet = userService.selectUserPermissions(userId);
info.addStringPermissions(permissionSet);
log.info("===============Shiro权限认证成功==============");
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
log.info("===============Shiro登录认证开始============");
//TODO: 校验token
String token = (String) authenticationToken.getCredentials();
if (StringUtils.isEmpty(token)) {
throw new AuthenticationException("token为空!");
}
//TODO:从token中取出用户名
String username = jwtTokenUtil.getUserNameFromToken(token);
if (org.apache.commons.lang3.StringUtils.isEmpty(username)) {
throw new AuthenticationException("token非法无效!");
}
//TODO: 判断用户是否存在
LoginUserVo loginUserVoVo = userService.selectLoginUserVoByLoginName(username);
if (ObjectUtils.isEmpty(loginUserVoVo)) {
throw new AuthenticationException("用户不存在!");
}
//TODO: 判断用户状态
if (loginUserVoVo.getStatus() == 1) {
throw new AuthenticationException("账号已被锁定,请联系管理员!");
}
//TODO:校验token是否超时失效
if (!jwtTokenUtil.validateToken(token, username)) {
throw new AuthenticationException("Token失效,请重新登录!");
}
log.info("===============Shiro登录认证成功============");
return new SimpleAuthenticationInfo(loginUserVoVo, token, getName());
}
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
}
}
通过代码实现拦截
@Configuration
public class ShiroJwtConfig {
@Resource(name = "shiroRedisTemplate")
private RedisTemplate redisTemplate;
@Value("${hdw.jwt.expiration}")
private int cacheLive;
@Value("${spring.application.name}")
private String cacheKeyPrefix;
@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器
Map filterChainDefinitionMap = new linkedHashMap();
//TODO:配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/sys/captcha", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
filterChainDefinitionMap.put("/sys/encrypt", "anon");//加密
filterChainDefinitionMap.put("/api*.js", "anon");
filterChainDefinitionMap.put("*.css", "anon");
filterChainDefinitionMap.put("*.html", "anon");
filterChainDefinitionMap.put("*.svg", "anon");
filterChainDefinitionMap.put("*.pdf", "anon");
filterChainDefinitionMap.put("*.jpg", "anon");
filterChainDefinitionMap.put("*.png", "anon");
filterChainDefinitionMap.put("*.ico", "anon");
//TODO:排除字体格式的后缀
filterChainDefinitionMap.put("*.ttf", "anon");
filterChainDefinitionMap.put("*.woff", "anon");
filterChainDefinitionMap.put("*.woff2", "anon");
filterChainDefinitionMap.put("/druid**", "anon");
filterChainDefinitionMap.put("/webjars
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置自定义缓存
securityManager.setCacheManager(shiroRedisCacheManager());
// 设置自定义realm
securityManager.setRealm(jwtRealm());
securityManager.setSubjectDAO(subjectDAO());
// 设置自定义会话
securityManager.setSessionManager(sessionManager());
return securityManager;
}
//创建自定义realm
@Bean
public Realm jwtRealm() {
JwtRealm jwtRealm = new JwtRealm();
jwtRealm.setCacheManager(shiroRedisCacheManager());
jwtRealm.setCachingEnabled(true);
return jwtRealm;
}
@Bean
public CacheManager shiroRedisCacheManager() {
ShiroRedisCacheManager redisCacheManager = new ShiroRedisCacheManager(cacheLive * 1000, cacheKeyPrefix + ":shiro-cache:", redisTemplate);
return redisCacheManager;
}
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setCacheManager(shiroRedisCacheManager());
//TODO:单位为毫秒(1秒=1000毫秒)设置为7天
sessionManager.setSessionValidationInterval(1000 * cacheLive);
//TODO: 设置全局session超时时间
sessionManager.setGlobalSessionTimeout(1000 * cacheLive);
//TODO:删除过期session
sessionManager.setDeleteInvalidSessions(true);
//TODO: 开启/禁用绘画验证
sessionManager.setSessionValidationSchedulerEnabled(false);
Simplecookie cookie = new Simplecookie();
//TODO:设置cookie名字,默认为JSESSIONID;
cookie.setName(cacheKeyPrefix + "-");
//TODO:设置cookie的域名,默认空,即当前访问的域名;
cookie.setDomain("");
//TODO:设置cookie的路径,默认空,即存储在域名根下;
cookie.setPath("");
//TODO:设置cookie的过期时间,单位为秒,默认-1表示关闭浏览器时过期cookie;
cookie.setMaxAge(cacheLive);
//TODO:如果设置为true,则客户端不会暴露给客户端脚本代码,使用Httponly cookie有助于减少某些类型的跨站点脚本攻击
cookie.setHttponly(true);
//TODO:sessionManager创建会话cookie的模板
sessionManager.setSessionIdcookie(cookie);
//TODO:是否启用/禁用Session Id cookie,默认是启用的;如果禁用后将不会设置Session Id cookie,即默认使用了Servlet容器的JSESSIONID,且通过URL重写(URL中的“;JSESSIonID=id”部分)保存Session Id。
sessionManager.setSessionIdcookieEnabled(false);
return sessionManager;
}
@Bean
public DefaultSubjectDAO subjectDAO() {
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageevaluator sessionStorageevaluator = new DefaultSessionStorageevaluator();
sessionStorageevaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageevaluator(sessionStorageevaluator);
return subjectDAO;
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
以上拦截认证授权的具体业务场景可以从各自的实际情况进行修改



