SpringSecurity基于源码扩展一套系统多套登录逻辑(二十二)

在有些项目中一套系统可能有多套登录逻辑

比如

/manage/** 管理后台相关接口走后台认证

/h5/api/** 小程序相关接口走token认证

spring-security源码-初始化(九)

1.在"5.WebSecurityConfiguration首先会初始化一个webSecurity管理我们定义的WebSecurityConfigurerAdapter子类"我们可以看到先初始化WebSecurity 并将我们自定义配置SpringSecurity的WebSecurityConfigurerAdapter设置成WebSecurity的configures WebSecurityConfigurerAdapter本质也是一个builder

2.在”org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#springSecurityFilterChain"处会调用WebSecurity.build方法构建springSecurityFilterChain

3.build内部先调用init,init方法会遍历configures也就是我们的WebSecurityConfiguration的init方法源码处<2>

  3.1  WebSecurityConfigurerAdapter的init方法会初始化HttpSecurity 同时也会调用configure方法允许我们自定义HttpSecurityConfig和AuthenticationManagerBuilder源码处<8>

  3.2最终将HttpSecurity(本质也是一个build) add到webSecurity的securityFilterChainBuilder源码处<6>

4.调用webSecurity.performBuild方法 会循环调用securityFilterChainBuilder也就是HttpSecurity的build方法构建出SecurityFilterChain add 到securityFilterChains

  4.1SecurityFilterChain维护了一批Filter  以及这个SecurityFilterChain的匹配规则 比如/manage/** 或者/h5/api/**   默认是是AnyRequest

通过以上源码知识我们可以定义多个WebSecurityConfigurerAdapter实现生成多个SecurityFilterChain并且定义匹配规则

以下就是处理不同url的不同登录逻辑 HttpSessionSecurityContextRepository是因为源码Spring-security源码-Filter之SecurityContextPersistenceFilter(十一)

默认是HttpSessionSecurityContextRepository来负责读取和写入保存当前会话,但是key如果我们没有定义的话默认都是使用同一个SPRING_SECURITY_CONTEXT

UserSecurityConfig

@Configuration
@Order(1)
public class UserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         *  inMemoryAuthentication 开启在内存中定义用户
         *  多个用户通过and隔开
         */
        auth.inMemoryAuthentication()
                .withUser("liqiang").password("liqiang").roles("admin")
                .and()
                .withUser("admin").password("admin").roles("admin");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        RequestMatcher requestMatcher=new AntPathRequestMatcher("/user/**");
        HttpSessionSecurityContextRepository httpSessionSecurityContextRepository= new HttpSessionSecurityContextRepository();
        httpSessionSecurityContextRepository.setSpringSecurityContextKey("user");
                http.securityContext().securityContextRepository(httpSessionSecurityContextRepository).and().
                        requestMatcher(requestMatcher)
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().rememberMe()//记住登录
                .tokenRepository(new InMemoryTokenRepositoryImpl())
                .and()
                .formLogin()// rm表单的方式
                .loginPage("/user/login")//登录页面路径
                .loginProcessingUrl("/user/doLogin")
                //自定义登录请求地址
                .defaultSuccessUrl("/user/hello")
                .usernameParameter("loginName")
                .passwordParameter("loginPassword")
                .permitAll(true)//不拦截
                .and()
                .csrf()//记得关闭
                .disable()
                .sessionManagement().
                 maximumSessions(1)
                .maxSessionsPreventsLogin(true);
    }


}

ProductSecurityConfig

@Configuration
@Order(0)
public class ProductSecurityConfig  extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         *  inMemoryAuthentication 开启在内存中定义用户
         *  多个用户通过and隔开
         */
        auth.inMemoryAuthentication()
                .withUser("liqiang").password("liqiang").roles("admin")
                .and()
                .withUser("admin").password("admin").roles("admin");
    }



    @Override
    protected void configure(HttpSecurity http) throws Exception {
        RequestMatcher requestMatcher=new AntPathRequestMatcher("/product/**");
        HttpSessionSecurityContextRepository httpSessionSecurityContextRepository= new HttpSessionSecurityContextRepository();
        httpSessionSecurityContextRepository.setSpringSecurityContextKey("product");
        http.requestMatcher(requestMatcher).securityContext().securityContextRepository(httpSessionSecurityContextRepository).and().authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().rememberMe()//记住登录
                .tokenRepository(new InMemoryTokenRepositoryImpl())
                .and()
                .formLogin()// rm表单的方式
                .loginPage("/product/login")//登录页面路径
                .loginProcessingUrl("/product/doLogin")
                //自定义登录请求地址
                .defaultSuccessUrl("/product/hello")
                .usernameParameter("loginName")
                .passwordParameter("loginPassword")
                .permitAll(true)//不拦截
                .and()
                .csrf()//记得关闭
                .disable()
                .sessionManagement().
                maximumSessions(1)
                .maxSessionsPreventsLogin(true);
    }


}
原文地址:https://www.cnblogs.com/LQBlog/p/15557457.html