SpringBoot(39) —— Shiro实现登陆拦截

2023年4月28日13:06:53

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()
  • 测试
    SpringBoot(39) —— Shiro实现登陆拦截
    SpringBoot(39) —— Shiro实现登陆拦截
    但是只有第一次点击链接的时候会传递sessionid,后面直接重定向到login.jsp
    SpringBoot(39) —— Shiro实现登陆拦截
    SpringBoot(39) —— Shiro实现登陆拦截

  • 由于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>&nbsp;码:<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");
    

SpringBoot(39) —— Shiro实现登陆拦截


  • 注意:上面只是实现了登陆拦截,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"
  • 作者:原来是小别扇
  • 原文链接:https://blog.csdn.net/Jzandth/article/details/108917686
    更新时间:2023年4月28日13:06:53 ,共 3435 字。