shiro安全控制目录
前后端分离的架构中,采用的是Token的无状态认证模式。
1. Maven依赖
org.apache.shiro
shiro-core
1.2.3
org.apache.shiro
shiro-web
1.2.3
org.apache.shiro
shiro-spring
1.2.3
2. 配置
在普通的Spring项目中,Filter是由Servlet管理,需要我们在web.xml配置。但是在SpringBoot2.x中,所有的Servlet或者Filter 的Beans都会被servlet容器自动注册。
(1)shiro要配置一个servlet Filter,过滤所有的请求。
org.apache.shiro.spring.web.ShiroFilterFactoryBean
是一个BeanFactory,实际返回bean为getObject()
返回值,也就是org.apache.shiro.web.servlet.AbstractShiroFilter
对象(Servlet Filter的子类)。
@Bean(name="shiroFilterFactoryBean")
public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager); //设置安全管理器
shiroFilterFactoryBean.setLoginUrl("/login");// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setSuccessUrl("/index"); // 登录成功后要跳转的链接
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");//未授权界面;
Map filterMap = new HashMap();
filterMap.put("/css/**","anon");
filterMap.put("/layui/**","anon");
filterMap.put("/img/**","anon");
filterMap.put("/js/**","anon");
filterMap.put("/html/**","anon");
filterMap.put("/login/index","authc");
filterMap.put("/login/login","anon");
filterMap.put("/logout","logout");//配置退出 过滤器,其中的具体的退出代码Shiro已经实现
filterMap.put("/**","authc");//过滤链定义,从上向下顺序执行,一般将/**放在最为下边
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean ;
}
(2)shiro需要配置SecurityManager,协调管理所有组件。
shiro通过servlet Filter过滤所有的请求,但是如何去协调管理或自定义配置诸如(Realm、SessionManager、rememberMananger、CacheManager)组件,需要由SecurityMananger这位shiro大管家操心。
- SubjectContext在创建的时候,需要关闭session的创建,这个由
DefaultWebSubjectFactory
的createSubject
进行管理。 - 禁用Session作为存储的实现,这个主要由
subjectDAO
的sessionStorageEvaluator
进行管理。 - 禁用session调度器,主要用
sessionManager
进行管理。
@Bean
public SecurityManager securityManager(DefaultWebSubjectFactory jwtDefaultSubjectFactory, DefaultWebSessionManager sessionManager, DefaultSubjectDAO defaultSubjectDAO) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//配置Realm
securityManager.setRealm(userAuthorizingRealm);
//配置SubjectFactory,禁止创建Session
securityManager.setSubjectFactory(jwtDefaultSubjectFactory);
//配置sessionManager
securityManager.setSessionManager(sessionManager);
//配置SubjectDAO,subject禁止存储到session
securityManager.setSubjectDAO(defaultSubjectDAO);
return securityManager;
}
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionIdCookieEnabled(false);
sessionManager.setSessionValidationSchedulerEnabled(false);
return sessionManager;
}
@Bean
public DefaultSubjectDAO defaultSubjectDAO() {
return new DefaultSubjectDAO() {
@Override
protected boolean isSessionStorageEnabled(Subject subject) {
return false;
}
};
}
@Bean
public DefaultWebSubjectFactory jwtDefaultSubjectFactory() {
return new JwtDefaultSubjectFactory() {
@Override
public Subject createSubject(SubjectContext context) {
// 不创建session
context.setSessionCreationEnabled(false);
Subject subject = super.createSubject(context);
return subject;
}
};
}
@Bean
public UserAuthorizingRealm userAuthorizingRealm(){
UserAuthorizingRealm userAuthorizingRealm = new UserAuthorizingRealm();
//暂时不使用缓存
userAuthorizingRealm.setAuthorizationCachingEnabled(false);
return userAuthorizingRealm;
}
(3)自定义shiroFilter
在shiro中可以自定义过滤器链,对url进行精细化的控制。shiro Filter也是Servlet Filter的子类。使用@Bean将Shiro Filter Bean加入到容器时,Filter会自动注册到Servlet Filter Chain中,并且拦截路径默认为/。需要取消Filter的自动注册,手动的加入到Shiro Filter Chain中。
//自定义权限过滤器
@Bean
public FilterRegistrationBean myPermissionFilterBean(MyPermissionFilter myPermissionFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean(myPermissionFilter);
//取消自动注册
registration.setEnabled(false);
return registration;
}
shiro(7)-shiroFilter(url上的权限控制)
也可以动态的配置过滤器链。
@Bean("shiroFilterBean")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setFilterChainDefinitionMap(section);
Map filterMap = new HashMap() {{
put("authcFilter", myAuthcFilter);
put("permissionFilter", myPermissionFilter);
}};
shiroFilterFactoryBean.setFilters(filterMap);
return shiroFilterFactoryBean;
}
@Bean
public ChainDefinitionSectionMetaSource section(){
//FactoryBean的子类,动态的拼装org.apache.shiro.config.Ini.Section类型。
return new ChainDefinitionSectionMetaSource();
}
ChainDefinitionSectionMetaSource 代码参考
(4)启动方法注解
在方法上可以使用注解来开启权限控制,实际上是AOP的实现之一
/**
* 开启aop注解支持
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
文章参考
Springboot与shiro整合遇到的坑
106.2 Spring Boot之Shiro无状态(2)【从零开始学Spring Boot】
spring boot 2.0 集成 shiro 和 pac4j cas单点登录