Spring Security--多个过滤器链和多个用户表

 请求从客户端出发,到达客户端,也就是servlet,中间有很多过滤器的,其中就有一个过滤器链代理,里面包含了过滤器的一个集合。而且Spring Security Filter并不是直接嵌入到Web Filter中的,而是通过FilterChainProxy 来统一管理 Spring Security Filter, FilterChainProxy 本身则通过 Spring提供的 DelegatingFilterProxy代理过滤器嵌入到Web Filter之中。

 可以看到,当请求到达FilterChainProxy之后,FilterChainProxy 会根据请求的路径,将请求转发到不同的Spring Security Filters 上面去,不同的Spring Security Filters 对应了不同的过滤器,也就是不同的请求将经过不同的过滤器。

对项目进行简单的改造

 如果访问/web/hello这个路径,Security处理器执行链中将不包含SessionManagementFilter

如果访问/v1/hello这个路径,Security处理器执行链中包含SessionManagementFilter

也就是一组对照实验,我们后面再配置两条过滤器链,分别区分这两个接口,看看两条链是否都生效,第一个接口是可以开启多个会话的,第二个是不允许的。

 @Bean
    SecurityFilterChain securityFilterChain1(HttpSecurity httpSecurity)  throws Exception{
        httpSecurity.antMatcher("/web/**").authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                //配置处理登录请求的接口,其实就是配置了过滤器里的拦截规则,将来的登录请求就会在过滤器中被处理
                .loginProcessingUrl("/web/login")
                //配置登录表单中用户名的 key
                .usernameParameter("username")
                //配置登录表单中的密码 默认也是username 和 password
                .passwordParameter("password")
                .successHandler((request, response, authentication) -> {
                    response.setContentType("application/json;charset=utf-8");
                    ResBean resBean = ResBean.ok("登陆成功web");
                    String s = new ObjectMapper().writeValueAsString(resBean);
                    response.getWriter().write(s);
                })
                .and()
                .sessionManagement()
                //设置会话的最大并发数
                .maximumSessions(1)
                //达到最大登录数后,是否要阻止下一个登录
                .maxSessionsPreventsLogin(true)
                //关闭默认的csrf认证
                .and()
                .and()
                .csrf().disable();
        return httpSecurity.build();
    }
    @Bean
    SecurityFilterChain securityFilterChain2(HttpSecurity httpSecurity)  throws Exception{
        httpSecurity.antMatcher("/v1/**").authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                //开始配置登录表单
                .formLogin()
                //配置登录页面,如果访问了一个需要登录以后才能访问的页面,那么就会自动登录到这个页面
                .loginPage("/login.html")
                //配置处理登录请求的接口,其实就是配置了过滤器里的拦截规则,将来的登录请求就会在过滤器中被处理
                .loginProcessingUrl("/v1/login")
                //配置登录表单中用户名的 key
                .usernameParameter("username")
                //配置登录表单中的密码 默认也是username 和 password
                .passwordParameter("password")
                //配置登录成功后访问的接口
                .successHandler((request, response, authentication) -> {
                    response.setContentType("application/json;charset=utf-8");
                    ResBean resBean = ResBean.ok("登陆成功v1");
                    String s = new ObjectMapper().writeValueAsString(resBean);
                    response.getWriter().write(s);
                })
                .and()
                .sessionManagement().disable()
                //关闭默认的csrf认证
                .csrf().disable();
        return httpSecurity.build();
    }

 红框里的就是已经添加的过滤器链,感兴趣的可以自己在记事本打开看看。

注意的是,规则一定要统一,一条执行链的规则,如/web/**,下面一切的接口都加/web/**,包括登录的接口

 

 我们再去浏览器登一下看看效果,/web的是设置了最大会话数的,v1的没有设置

 报错了

第二个请求肯定是成功的,这里留给大家自己尝试。

再就是多用户了,security也是支持的,也就是有多个UserService

 可以是UserService1,UserService2

然后分别注入不同的过滤器执行链中,如下

 上图,我直接在内存中写了个用户,模拟不同表的用户,下面是数据库的用户登录。

 效果就是对应的UserService只能登上对应的过滤器链。

也就是lisi这个账号只能上/v1,admin只能上/web

想看效果的同学可以再复制一个UserService2出来,

 

 这样就能看出效果了,

admin这个账号就哪也登不上了,

zhangsan只能登/web这条链,

lisi也只能登/v1这条链

 

 上图回到了登录页,说明登录失败。

 总结一下,当出现多个userService时,过滤器执行链选择了哪个,就只会用那一个userService。另外。

 希望大家看完能有所收获。最后贴个demo代码吧security_demo: 一个简单详细的security的学习项目

猜你喜欢

转载自blog.csdn.net/a2285786446/article/details/131200268