package com.nms.swspkmas_standalone.shiro.config;
|
|
|
import com.nms.swspkmas_standalone.filter.JwtFilter;
|
import com.nms.swspkmas_standalone.shiro.JwtCredentialsMatcher;
|
import com.nms.swspkmas_standalone.shiro.realm.JwtRealm;
|
import com.nms.swspkmas_standalone.shiro.realm.ShiroRealm;
|
import org.apache.shiro.authc.credential.CredentialsMatcher;
|
import org.apache.shiro.authc.pam.AuthenticationStrategy;
|
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
|
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
|
import org.apache.shiro.authz.Authorizer;
|
import org.apache.shiro.authz.ModularRealmAuthorizer;
|
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
import org.apache.shiro.mgt.DefaultSubjectDAO;
|
import org.apache.shiro.mgt.SecurityManager;
|
import org.apache.shiro.mgt.SessionStorageEvaluator;
|
import org.apache.shiro.realm.Realm;
|
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.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Configuration;
|
|
import javax.servlet.Filter;
|
import java.util.ArrayList;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
|
|
@Configuration
|
public class ShiroConfig {
|
|
/**
|
* 交由 Spring 来自动地管理 Shiro-Bean 的生命周期
|
*
|
* 注解式的权限控制需要配置两个Bean,第一个是AdvisorAutoProxyCreator,代理生成器,需要借助SpringAOP来扫描@RequiresRoles和@RequiresPermissions等注解,生成代理类实现功能增强,从而实现权限控制。需要配合AuthorizationAttributeSourceAdvisor一起使用,否则权限注解无效。
|
*/
|
@Bean
|
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
|
return new LifecycleBeanPostProcessor();
|
}
|
|
/**
|
* 为 Spring-Bean 开启对 Shiro 注解的支持
|
*/
|
@Bean
|
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
|
return authorizationAttributeSourceAdvisor;
|
}
|
|
@Bean
|
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
|
DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
|
app.setProxyTargetClass(true);
|
return app;
|
|
}
|
|
/**
|
* 不向 Spring容器中注册 JwtFilter Bean,防止 Spring 将 JwtFilter 注册为全局过滤器
|
* 全局过滤器会对所有请求进行拦截,而本例中只需要拦截除 /login 和 /logout 外的请求
|
* 另一种简单做法是:直接去掉 jwtFilter()上的 @Bean 注解
|
*/
|
@Bean
|
public FilterRegistrationBean<Filter> registration(JwtFilter filter) {
|
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>(filter);
|
registration.setEnabled(false);
|
return registration;
|
}
|
|
@Bean
|
public JwtFilter jwtFilter() {
|
//过滤器如果加了@Compoent就没必要用这个方法了
|
return new JwtFilter();
|
}
|
|
/**
|
* 配置访问资源需要的权限
|
*/
|
@Bean
|
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
|
|
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
|
//给工厂bean设置web安全管理器
|
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
|
shiroFilterFactoryBean.setLoginUrl("/api/account/login");
|
shiroFilterFactoryBean.setSuccessUrl("/authorized");
|
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
|
|
// 添加 jwt 专用过滤器,拦截除 /login 和 /logout 外的请求
|
/*Map<String, Filter> filterMap = new LinkedHashMap<>();
|
filterMap.put("jwtFilter", jwtFilter());
|
shiroFilterFactoryBean.setFilters(filterMap);*/
|
|
//配置系统受限资源以及公共资源
|
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
|
//放行Swagger2页面,需要放行这些
|
filterChainDefinitionMap.put("/api/images/**","anon");
|
filterChainDefinitionMap.put("/api/account/login","anon");
|
filterChainDefinitionMap.put("/api/capture-record/addCaptureRecord","anon");
|
filterChainDefinitionMap.put("/api/examinee/getExaminee","anon");
|
|
filterChainDefinitionMap.put("/swagger-ui.html","anon");
|
filterChainDefinitionMap.put("/swagger/**","anon");
|
filterChainDefinitionMap.put("/webjars/**", "anon");
|
filterChainDefinitionMap.put("/swagger-resources/**","anon");
|
|
filterChainDefinitionMap.put("/static/**", "anon");
|
|
filterChainDefinitionMap.put("/doc.html", "anon");
|
filterChainDefinitionMap.put("/v2/api-docs", "anon");
|
|
filterChainDefinitionMap.put("/logout", "logout"); // 退出登录
|
filterChainDefinitionMap.put("/**", "jwtFilter,authc"); // 需登录才能访问
|
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
return shiroFilterFactoryBean;
|
}
|
|
/**
|
* 配置 ModularRealmAuthenticator
|
*/
|
@Bean
|
public ModularRealmAuthenticator authenticator() {
|
ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
|
// 设置多 Realm的认证策略,默认 AtLeastOneSuccessfulStrategy
|
AuthenticationStrategy strategy = new FirstSuccessfulStrategy();
|
authenticator.setAuthenticationStrategy(strategy);
|
return authenticator;
|
}
|
|
/**
|
* 禁用session, 不保存用户登录状态。保证每次请求都重新认证
|
*/
|
@Bean
|
protected SessionStorageEvaluator sessionStorageEvaluator() {
|
DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
|
sessionStorageEvaluator.setSessionStorageEnabled(false);
|
return sessionStorageEvaluator;
|
}
|
|
/**
|
* JwtRealm 配置,需实现 Realm 接口
|
*/
|
@Bean
|
JwtRealm jwtRealm() {
|
JwtRealm jwtRealm = new JwtRealm();
|
// 设置加密算法
|
CredentialsMatcher credentialsMatcher = new JwtCredentialsMatcher();
|
// 设置加密次数
|
jwtRealm.setCredentialsMatcher(credentialsMatcher);
|
return jwtRealm;
|
}
|
|
/**
|
* ShiroRealm 配置,需实现 Realm 接口
|
*/
|
// @Bean
|
// ShiroRealm shiroRealm() { //这里其实是模拟的数据库的类,但是也继承了AuthorizingRealm
|
// ShiroRealm shiroRealm = new ShiroRealm();
|
// // 设置加密算法
|
// HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher("SHA-1");
|
// // 设置加密次数
|
// credentialsMatcher.setHashIterations(16);
|
// shiroRealm.setCredentialsMatcher(credentialsMatcher);
|
// return shiroRealm;
|
// }
|
|
@Bean
|
ShiroRealm shiroRealm() { //这里其实是模拟的数据库的类,但是也继承了AuthorizingRealm
|
ShiroRealm shiroRealm = new ShiroRealm();
|
return shiroRealm;
|
}
|
|
/**
|
* 配置 DefaultWebSecurityManager
|
*/
|
@Bean
|
public DefaultWebSecurityManager securityManager() {
|
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
|
// 1.Authenticator
|
securityManager.setAuthenticator(authenticator());
|
|
// 2.Realm
|
List<Realm> realms = new ArrayList<Realm>(16);
|
realms.add(jwtRealm());
|
realms.add(shiroRealm());
|
securityManager.setRealms(realms); // 配置多个realm
|
|
// 3.关闭shiro自带的session
|
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
|
subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator());
|
securityManager.setSubjectDAO(subjectDAO);
|
|
return securityManager;
|
}
|
|
@Bean
|
public Authorizer authorizer(){
|
//这里是个坑,如果没有这个bean,启动会报错,所以得加上
|
return new ModularRealmAuthorizer();
|
}
|
|
|
}
|