1.实现登陆拦截
-
实现登陆拦截其实就是使用shiro拦截没有经过认证的用户的请求,当用户在没有认证的情况下就请求资源时,就将其重定向到登陆认证页面,这一点和spring security一样
-
要实现认证+授权,本质上还是在使用过滤器/拦截器,而spring security只是把这些都封装好了,我们直接调用封装之后的方法就可以使用;而Shiro对于过滤器/拦截器的封装没有spring security那么彻底,所以我们需要在刚刚创建的config中的ShiroFilterFactoryBean中配置我们要加上的过滤器/拦截器来实现认证+授权
-
shiro中有如下5种常用过滤器(shiro常用过滤器)
- anon:无需认证即可访问
- authc:必须认证才能访问
- user:必须有"记住我"功能才能访问【几乎不用】
- perms:拥有对某个资源的访问权限才能访问【比如某系资源只有管理员可以访问】
- role:拥有某个角色才能访问
-
shiro中过滤器的使用语法:map集合.put(“需要过滤的URL”,“要使用的过滤器”)
-
配置过滤器
//这是上一篇博客写好的装配到spring容器中的ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(securityManager); return bean; }
-
配置我们指定的过滤器需要调用bean.setFilterChainDefinitionMap(),即为设置过滤器链需要向这个方法中传入一个Map集合,我们可以查看这个方法的定义
public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) { this.filterChainDefinitionMap = filterChainDefinitionMap; }
-
可见确实需要传入一个Map集合,所以在shiroFilterFactoryBean()中定义一个Map集合,将我们要设置的过滤器装入,并传入方法setFilterChainDefinitionMap()中
//3、装配realm实例到spring容器中 ShiroFilterFactoryBean,这个实例要关联我们装配到spring容器中的DefaultWebSecurityManager实例,所以它最后写 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(securityManager); /* * - anon:无需认证即可访问 * - authc:必须认证才能访问 * - user:必须有"记住我"功能才能访问【几乎不用】 * - perms:拥有对某个资源的访问权限才能访问【比如某系资源只有管理员可以访问】 * - role:拥有某个角色才能访问 * */ Map<String, String> filterMap = new LinkedHashMap<String, String>(); filterMap.put("/user/add","authc"); filterMap.put("/user/update","authc"); //配置过滤器 bean.setFilterChainDefinitionMap(filterMap); return bean; }
-
可以发现我们做的事情很简单
- 定义一个map
- 向map中存值,其中key为需要拦截的请求,value为放行的条件,需要条件什么请求的拦截直接put进去即可
- 将map集合作为参数传入setFilterChainDefinitionMap()
-
测试
但是只有第一次点击链接的时候会传递sessionid,后面直接重定向到login.jsp
-
由于shiro没有自带一个登陆页面可以给我们测试,所以我们需要自己写一个登陆页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登陆</h1> <hr> <form action=""> <p>用户名:<input type="text" name="username"></p> <p>密 码:<input type="password" name="password"></p> <p><input type="submit"></p> </form> </body> </html>
-
为这个登陆页写上controller视图跳转方法
@RequestMapping("toLogin") public String loginPage(){ return "login"; }
-
设置拦截未登录的用户之后自动跳转登录页,刚刚确实是自动跳转了login.jsp,但是我们现在不使用jsp了,所以我们需要指定自动跳转我们刚刚创建的登陆页面;直接在我们创建的ShiroConfig中的shiroFilterFactoryBean()中添加一条ShiroFilterFactoryBean对象的配置
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(securityManager); bean.setLoginUrl("/toLogin");
- 注意:上面只是实现了登陆拦截,form表单的提交地址还没有填写,在写一篇博客中实现
- 再来就是为什么我们没有创建登陆页面的时候,被拦截之后会被重定向到"/login.jsp"呢?看ShiroFilterFactoryBean源码即可了解
- 这个类有一个方法叫applyLoginUrlIfNecessary(),源码如下
private void applyLoginUrlIfNecessary(Filter filter) { String loginUrl = getLoginUrl(); if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) { AccessControlFilter acFilter = (AccessControlFilter) filter; //only apply the login url if they haven't explicitly configured one already: //仅在尚未显式配置登录url的情况下应用登录url String existingLoginUrl = acFilter.getLoginUrl(); if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) { acFilter.setLoginUrl(loginUrl); } } }
- 从设置方法我们可以发现,当我们没有显式的配置一个登陆页面的url的时候,它就会将登陆页面的url默认的设置为AccessControlFilter.DEFAULT_LOGIN_URL,我们可以去看看这个常量的值
public static final String DEFAULT_LOGIN_URL = "/login.jsp";
- 可见,默认设置的登陆页面URL就是"/login.jsp",所以我们没有显式的配置登陆页面的url的时候会被重定向到"/login.jsp"