SpringSecurity 는 springBoot,redis 를 통합 하여 로그 인 상호 차기 기능 을 실현 합 니 다.

배경
나의 문장 에 기초 하여--SpringSecurity 통합 springBoot,redis token 동적 url 권한 검사실현 하고 자 하 는 기능 은 한 사용자 가 두 대의 설비 에 동시에 로그 인 할 수 없다 는 것 을 실현 하 는 것 이다.두 가지 사고방식 이 있다.
(1)이후 의 로그 인 은 앞의 로그 인 을 자동 으로 차 버린다.
(2)만약 에 사용자 가 로그 인 을 했다 면 후발 주자 의 로그 인 을 허용 하지 않 는 다.
특히 프로젝트 의 기 초 는 redis 가 유지 하 는 session 입 니 다.
redisHttpSession 설정
spring session 을 redis 에서 관리 하도록 설정 합 니 다.
2.1 yml 의 http session 설정 을 제거 하고 yml 과 주 해 는 둘 중 하나 만 선택 합 니 다(동시에 설정 하고 주해 설정 만 유효 합 니 다).왜 yml 을 사용 하지 않 는 지 에 대해 서 는 잠시 후에 언급 하 겠 습 니 다.
在这里插入图片描述
2.2 webSecurity Config 에 주석 추가@EnableRedisHttpSession
在这里插入图片描述

@EnableRedisHttpSession(redisNamespace = "spring:session:myframe", maxInactiveIntervalInSeconds = 1700
        , flushMode = FlushMode.ON_SAVE)
로그 인 한 결과 redis session namespace 가 저희 가 이름 을 지 었 습 니 다.
在这里插入图片描述
redis 관리 session Repository 가 져 오기
사용자 의 로그 인 을 제한 하려 면 시스템 에 있 는 모든 session 을 가 져 와 야 합 니 다.
2.spring Session 홈 페이지 의 문 서 를 다시 봅 니 다.springsession 홈 페이지 제공 문서https://docs.spring.io/spring-session/docs/   2.2.2.RELEASE/reference/html5/#api-findbyindexnamesessionrepository
SessionRepository 실현 도 FindByIndexNameSsionRepository 실현 을 선택 할 수 있 습 니 다.
FindByIndexNameSsionRepository 는 주어진 색인 이름과 색인 값 을 가 진 모든 세 션 을 찾 는 방법 을 제공 합 니 다.
FindByIndexNameSsionRepository 가 실 현 될 때 특정 사용자 의 모든 세 션 을 편리 하 게 찾 을 수 있 습 니 다.

/**
     * redis  sessionRepository
     * RedisIndexedSessionRepository   FindByIndexNameSessionRepository  
     */
    @Autowired
    //  @Lazy          ...
    // Circular reference involving containing bean '.RedisHttpSessionConfiguration' 
    @Lazy   
    private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
여기 서 주의 하 세 요.yml 을 통 해 redis session 을 설정 하면 session Repository 아래 에 빨 간 선 이 있 습 니 다.
在这里插入图片描述
운행 에 영향 을 주지 않 지만 강박 증 이 있 으 므 로@EnableWebSecurity 주석 으로 바 꿉 니 다(왜 요?나 도 알 고 싶 지 않다.
session Repository 를 SpringSession Backed Session Registry 에 주입 합 니 다.
spring session 이 Spring Security 에 제공 하 는 어떤 세 션 을 병행 하 는 세 션 레 지 스 트 입 니 다.아마도 spring Security 에 게 로그 인 을 제한 하 라 고 했 을 것 입 니 다.session Repository 만 으로 는 안 되 고 도 구 를 추가 해 야 합 니 다.
webSecurity Config 가입:

/**
     *  spring session Spring Security   ,
     *                       
     * @return
     */
    @Bean
    public SpringSessionBackedSessionRegistry sessionRegistry(){
        return new SpringSessionBackedSessionRegistry<>(sessionRepository);
    }
주:
https://blog.csdn.net/qq_34136709/article/details/106012825 이 글 은 Http Session Event Publisher 를 추가 하여 session 을 감청 하여 구름 을 없 애 야 한다 고 말 했 습 니 다.아마 제 가 redis session 을 사 용 했 기 때 문 일 것 입 니 다.이것 이 필요 하지 않 습 니 다.필요 하면 잘못 보고 할 것 입 니 다.무슨 잘못 입 니까?까 먹 었 어.
세 션 만 료 후 처리 클래스 추가
먼저 CustomSession InformationExpired Strategy.java 를 만 들 고 session 이 만 료 된 후에 전단 의 처리 류 를 어떻게 알 리 는 지 알 립 니 다.내용 은 다음 과 같 습 니 다.

public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
        if (log.isDebugEnabled()) {
           log.debug("{} {}", event.getSessionInformation(), MessageConstant.SESSION_EVICT);
        }
        HttpServletResponse response = event.getResponse();
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
        String responseJson = JackJsonUtil.object2String(ResponseFactory.fail(CodeMsgEnum.SESSION_EVICT, MessageConstant.SESSION_EVICT));
        response.getWriter().write(responseJson);
    }
}
주:일반적으로 스스로 전단 으로 돌아 가 는 정 보 를 다시 쓰 고 프레임 으로 던 지 는 오류 정 보 를 직접 쓰 지 않 습 니 다.
configure(HttpSecurity http)방법 에 설정

.csrf().disable()
//    
.sessionManagement()
//     session       
//.sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(httpSessionConfig.sessionRegistry()))
.maximumSessions(1)
.sessionRegistry(sessionRegistry())
.maxSessionsPreventsLogin(false) //false       ,        
//session       (        )
.expiredSessionStrategy(new CustomSessionInformationExpiredStrategy()); 
주의:https://blog.csdn.net/qq_34136709/article/details/106012825 이 글 은 session 인증 의 원 리 를 말 합 니 다.저 는 session 의 인증 전략 을 실 행 했 지만 debug 에 대응 하 는 코드 를 보 았 을 때
在这里插入图片描述
이 session 인증 전략 은 Null Authenticated Session Strategy 이지 Concurrent Session Control Authentication Strategy 가 아 닙 니 다.그 러 니까 이 session 인증 정책 을 어디서 설정 해 야 합 니까?configure(HttpSecurity http)의 설정 이 제일 먼저 생각 났 어 요.
在这里插入图片描述
결 과 는 무효 입 니 다.그 후에 다른 사람의 코드 를 보고 이 전략 은 로그 인 할 때 추가 해 야 한다 고 생각 했 습 니 다.우리 의 로그 인 은 보통 자신 이 다시 써 야 합 니 다.자 연 스 럽 게 위의 쓰기 가 무효 가 될 것 입 니 다.그래서 나 는 사용자 정의 로그 인 필 터 를 찾 았 다.
在这里插入图片描述
在这里插入图片描述
그리고 this.setSession AuthenticationStrategy(session Strategy)를 발견 합 니 다.확실히 존재 한다.

public LoginFilter(UserVerifyAuthenticationProvider authenticationManager,
                       CustomAuthenticationSuccessHandler successHandler,
                       CustomAuthenticationFailureHandler failureHandler,
                       SpringSessionBackedSessionRegistry springSessionBackedSessionRegistry) {
        //       (            )
        this.authenticationManager = authenticationManager;
        //           
        this.setAuthenticationSuccessHandler(successHandler);
        //           
        this.setAuthenticationFailureHandler(failureHandler);
        //  session    ( springSecurity  redis Session      )
        ConcurrentSessionControlAuthenticationStrategy sessionStrategy = new
                ConcurrentSessionControlAuthenticationStrategy(springSessionBackedSessionRegistry);
        //      session
        sessionStrategy.setMaximumSessions(1);
        this.setSessionAuthenticationStrategy(sessionStrategy);
        //          url
        super.setFilterProcessesUrl("/myLogin");
    }
시작 하 자마자 session 인증 정책 이 우리 가 설정 한 정책 으로 바 뀌 었 다 는 것 을 알 게 되 었 습 니 다.
완전한 웹 보안 Config 는 다음 과 같 습 니 다:

@Configuration
@EnableWebSecurity
//RedisFlushMode     :ON_SAVE(   response commit     ),IMMEDIATE(       ,     )
//yml         (    ,        )
@EnableRedisHttpSession(redisNamespace = "spring:session:myframe", maxInactiveIntervalInSeconds = 5000
        , flushMode = FlushMode.ON_SAVE)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserVerifyAuthenticationProvider authenticationManager;//     

    @Autowired
    private CustomAuthenticationSuccessHandler successHandler;//         

    @Autowired
    private CustomAuthenticationFailureHandler failureHandler;//         

    @Autowired
    private MyFilterInvocationSecurityMetadataSource securityMetadataSource;//    URL         
    @Autowired
    private MyAccessDecisionManager accessDecisionManager;//               


    /**
     * redis  sessionRepository
     * RedisIndexedSessionRepository   FindByIndexNameSessionRepository  
     */
    @Autowired
    //  @Lazy          ...
    // Circular reference involving containing bean '.RedisHttpSessionConfiguration'
    @Lazy
    private FindByIndexNameSessionRepository<? extends Session> sessionRepository;


    /**
     *  spring session Spring Security   ,
     *                       
     * @return
     */
    @Bean
    public SpringSessionBackedSessionRegistry sessionRegistry(){
        return new SpringSessionBackedSessionRegistry<>(sessionRepository);
    }

    /**
     *     
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     *    HttpSessionIdResolver Bean
     *         Response Header x-auth-token        sessionToken
     *  token              Request Header x-auth-token    sessionToken
     */
    @Bean
    public HttpSessionIdResolver httpSessionIdResolver() {
        return HeaderHttpSessionIdResolver.xAuthToken();
    }
    /**
     * Swagger          
     */
    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(
                "/*.html",
                "/favicon.ico",
                "/**/*.html",
                "/**/*.css",
                "/**/*.js",
                "/error",
                "/webjars/**",
                "/resources/**",
                "/swagger-ui.html",
                "/swagger-resources/**",
                "/v2/api-docs");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //                 ,       ,   securityMetadataSource  
                //.antMatchers("/demo/**", "/about/**").permitAll()
                //       URL           
                .anyRequest().authenticated()
                //          
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setAccessDecisionManager(accessDecisionManager);
                        object.setSecurityMetadataSource(securityMetadataSource);
                        return object;
                    }
                })
                .and()
                //      
                .logout().logoutUrl("/logout")
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                .clearAuthentication(true)
                .and()
                //                   
                .exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                //                       
                .accessDeniedHandler(new CustomAccessDeniedHandler())
                .and()
                //       
                .addFilter(new LoginFilter(authenticationManager, successHandler, failureHandler, sessionRegistry()))

                .csrf().disable()
                //    
                .sessionManagement()
                //     session       
                //.sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(httpSessionConfig.sessionRegistry()))
                .maximumSessions(1)
                .sessionRegistry(sessionRegistry())
                .maxSessionsPreventsLogin(false) //false       ,        
                //session       (        )
                .expiredSessionStrategy(new CustomSessionInformationExpiredStrategy());
        //    
        http.headers()
                .contentTypeOptions()
                .and()
                .xssProtection()
                .and()
                //    
                .cacheControl()
                .and()
                .httpStrictTransportSecurity()
                .and()
                //      frame        //   iframe     
                .frameOptions().disable();
    }

}
기타

@Lazy
private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
@lazy 를 추가 하지 않 고 어떤 순환 인용 을 할 지 에 대해 서 는 정말 신경 쓰 고 싶 지 않 습 니 다.오랫동안 봤 는데 누구 랑 누구 랑 순환 인용 이 일 어 났 는 지 모 르 겠 어 요...
SpringSecurity 통합 springBoot,redis-로그 인 서 로 를 실현 하 는 글 은 여기까지 소개 되 었 습 니 다.더 많은 SpringSecurity 로그 인 서 로 를 위 한 콘 텐 츠 는 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기