package cc.mrbird.febs.common.authentication;
|
|
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
|
import cc.mrbird.febs.common.properties.FebsProperties;
|
import lombok.RequiredArgsConstructor;
|
import org.apache.commons.lang3.StringUtils;
|
import org.apache.shiro.codec.Base64;
|
import org.apache.shiro.mgt.SecurityManager;
|
import org.apache.shiro.session.SessionListener;
|
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
import org.apache.shiro.web.mgt.CookieRememberMeManager;
|
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
import org.apache.shiro.web.servlet.SimpleCookie;
|
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.beans.factory.annotation.Value;
|
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Configuration;
|
import org.springframework.util.Base64Utils;
|
|
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collection;
|
import java.util.LinkedHashMap;
|
|
/**
|
* Shiro 配置类
|
*
|
* @author MrBird
|
*/
|
@Configuration
|
@RequiredArgsConstructor
|
public class ShiroConfig {
|
|
private final FebsProperties febsProperties;
|
|
@Value("${spring.redis.host}")
|
private String host;
|
@Value("${spring.redis.port}")
|
private int port;
|
@Value("${spring.redis.password:}")
|
private String password;
|
@Value("${spring.redis.timeout}")
|
private int timeout;
|
@Value("${spring.redis.database:0}")
|
private int database;
|
|
/**
|
* shiro 中配置 redis 缓存
|
*
|
* @return RedisManager
|
*/
|
private RedisManager redisManager() {
|
RedisManager redisManager = new RedisManager();
|
redisManager.setHost(host + ":" + port);
|
if (StringUtils.isNotBlank(password)) {
|
redisManager.setPassword(password);
|
}
|
redisManager.setTimeout(timeout);
|
redisManager.setDatabase(database);
|
return redisManager;
|
}
|
|
private RedisCacheManager cacheManager() {
|
RedisCacheManager redisCacheManager = new RedisCacheManager();
|
redisCacheManager.setRedisManager(redisManager());
|
return redisCacheManager;
|
}
|
|
@Bean
|
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
|
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
|
|
// 设置 securityManager
|
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
// 登录的 url
|
shiroFilterFactoryBean.setLoginUrl(febsProperties.getShiro().getLoginUrl());
|
// 登录成功后跳转的 url
|
shiroFilterFactoryBean.setSuccessUrl(febsProperties.getShiro().getSuccessUrl());
|
// 未授权 url
|
shiroFilterFactoryBean.setUnauthorizedUrl(febsProperties.getShiro().getUnauthorizedUrl());
|
|
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
|
// 设置免认证 url
|
String[] anonUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(febsProperties.getShiro().getAnonUrl(), ",");
|
for (String url : anonUrls) {
|
filterChainDefinitionMap.put(url, "anon");
|
}
|
// 配置退出过滤器,其中具体的退出代码 Shiro已经替我们实现了
|
filterChainDefinitionMap.put(febsProperties.getShiro().getLogoutUrl(), "logout");
|
|
filterChainDefinitionMap.put("/api/**", "anon");
|
|
filterChainDefinitionMap.put("/swagger-ui.html/**", "anon");
|
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
|
filterChainDefinitionMap.put("/v2/api-docs", "anon");
|
filterChainDefinitionMap.put("/webjars/**", "anon");
|
filterChainDefinitionMap.put("/wsxg", "anon");
|
|
// 除上以外所有 url都必须认证通过才可以访问,未通过认证自动访问 LoginUrl
|
filterChainDefinitionMap.put("/**", "user");
|
|
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
return shiroFilterFactoryBean;
|
}
|
|
@Bean
|
public SecurityManager securityManager(ShiroRealm shiroRealm) {
|
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
// 配置 SecurityManager,并注入 shiroRealm
|
securityManager.setRealm(shiroRealm);
|
// 配置 shiro session管理器
|
securityManager.setSessionManager(sessionManager());
|
// 配置 缓存管理类 cacheManager
|
securityManager.setCacheManager(cacheManager());
|
// 配置 rememberMeCookie
|
securityManager.setRememberMeManager(rememberMeManager());
|
return securityManager;
|
}
|
|
/**
|
* rememberMe cookie 效果是重开浏览器后无需重新登录
|
*
|
* @return SimpleCookie
|
*/
|
private SimpleCookie rememberMeCookie() {
|
// 设置 cookie 名称,对应 login.html 页面的 <input type="checkbox" name="rememberMe"/>
|
SimpleCookie cookie = new SimpleCookie("rememberMe");
|
// 设置 cookie 的过期时间,单位为秒,这里为一天
|
cookie.setMaxAge(febsProperties.getShiro().getCookieTimeout());
|
return cookie;
|
}
|
|
/**
|
* cookie管理对象
|
*
|
* @return CookieRememberMeManager
|
*/
|
private CookieRememberMeManager rememberMeManager() {
|
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
|
cookieRememberMeManager.setCookie(rememberMeCookie());
|
// rememberMe cookie 加密的密钥
|
String encryptKey = "febs_shiro_key";
|
byte[] encryptKeyBytes = encryptKey.getBytes(StandardCharsets.UTF_8);
|
String rememberKey = Base64Utils.encodeToString(Arrays.copyOf(encryptKeyBytes, 16));
|
cookieRememberMeManager.setCipherKey(Base64.decode(rememberKey));
|
return cookieRememberMeManager;
|
}
|
|
@Bean
|
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
|
return authorizationAttributeSourceAdvisor;
|
}
|
|
/**
|
* 用于开启 Thymeleaf 中的 shiro 标签的使用
|
*
|
* @return ShiroDialect shiro 方言对象
|
*/
|
@Bean
|
public ShiroDialect shiroDialect() {
|
return new ShiroDialect();
|
}
|
|
@Bean
|
public RedisSessionDAO redisSessionDAO() {
|
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
|
redisSessionDAO.setRedisManager(redisManager());
|
return redisSessionDAO;
|
}
|
|
/**
|
* session 管理对象
|
*
|
* @return DefaultWebSessionManager
|
*/
|
@Bean
|
public DefaultWebSessionManager sessionManager() {
|
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
|
Collection<SessionListener> listeners = new ArrayList<>();
|
listeners.add(new ShiroSessionListener());
|
// 设置 session超时时间
|
sessionManager.setGlobalSessionTimeout(febsProperties.getShiro().getSessionTimeout() * 1000L);
|
sessionManager.setSessionListeners(listeners);
|
sessionManager.setSessionDAO(redisSessionDAO());
|
sessionManager.setSessionIdUrlRewritingEnabled(false);
|
return sessionManager;
|
}
|
}
|