shiro框架是一个轻量级的安全框架,整合了会话管理、权限管理、角色管理等功能,封装程度高,API完善,使用方便。
但个人认为其框架的高度封装性也相应的导致了其学习难度的提升。
shiro过滤器
首先学习shiro要知道shiro框架在何时起作用的。
先上张图
可以看到项目启动的过程中出现了这么一句话 into shirofilter
我们再来看shiro过滤器的代码代码
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
//shiro 拦截器定义
System.out.println("into shirofilter...");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//拦截规则
filterChainDefinitionMap.put("/static/**","anon");
filterChainDefinitionMap.put("/logout","logout");
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
这里要注意以下几点:
-
shirofilter在项目启动时就开始影响,对项目的路径访问、登录、会话等开始起作用
-
shirofilter实质上是一个用来设置各种资源路径与其对应过滤规则的一个过滤器
-
filterChainDefinitionMap.put("/**",“authc”);一般放在所有put函数语句的最下面,用来对所有访问url进行权限过滤管理。所以要将不需要过滤的登录、注册、静态等url配置在它之前。
-
几个重要的set函数:
setLoginUrl() setSuccessUrl() setUnauthorizedUrl()
这几个简单的配置实际上是对一些特定条件的跳转设置,也就是一个看不见的控制器controller的配置,比如登陆成功的跳转、权限不足的跳转、登陆跳转等。 -
注意一点:filterChainDefinitionMap.put("/logout",“logout”)这一句,功能十分强大。它是你不需要自己写一个/logout的接口,shiro会帮你实现此接口并帮你实现解除当前用户登录的功能。执行/logout后页面会跳转到/login重新登录
完整过滤器代码如下:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
//shiro 拦截器定义
System.out.println("into shirofilter...");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//拦截规则
filterChainDefinitionMap.put("/static/**","anon");
filterChainDefinitionMap.put("/logout","logout");
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//使用md5算法
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(1);
return hashedCredentialsMatcher;
}
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager 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("UnauthorizedException","403");
return r;
}
}
重点就三个:shiroFilter、securityManager、myShiroRealm,以上三各部分就构成了一个最最简单的shiro配置类。
那么其他的Bean是用来干嘛的呢
- 首先是hashedCredentialsMatcher,他是一个凭证匹配器,也就是用来设置用户输入的密码是通过什么方式匹配到数据库中存储的密码。我们暂且认为他是一个转化器
- 下一个是authorizationAttributeSourceAdvisor,这个好理解,就是用来开启登录用户授权的,配置了这个bean,在访问某个权限路径是就会自动进入myShiroReal的中doGetAuthorizationInfo()方法进行获取权限。
- 最后一个simpleMappingExceptionResolver,看似可有可无,但他其实是用来配合shiro异常抛出的。简单来说,他就是一个异常handler,我们可以使用@ControllerAdvice去写一个功能相同的异常捕获与处理
@ControllerAdvice
public class ShiroExceptionHandler {
@ExceptionHandler(UnauthorizedException.class)
public String handleUnPermission(Exception e){
System.out.println("into ShiroExceptionHandler");
return "403";
}
}
如果既不写一个handler又不注册一个bean,那么当当前subject权限不足时,后台会报一个错误,这个错误表现为权限不足是页面无法跳转至相应的页面,这是许多人遇到的一个问题,保存信息如下:
2020-01-15 16:43:21.251 ERROR 8760 — [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [userInfo:add]] with root cause
org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method: public java.lang.String com.code.learn.controller.UserInfoController.userInfo()
所以这一个bean作用是十分重要的。大家两种方式都可以试一下
以上就是对shiroConfig配置的个人总结