JHipster 限制用户会话不适用于默认 JWT 配置

Posted

技术标签:

【中文标题】JHipster 限制用户会话不适用于默认 JWT 配置【英文标题】:JHipster limit user sessions not working with default JWT configuration 【发布时间】:2020-02-16 19:57:07 【问题描述】:

我一直在查看许多类似的问题,但似乎没有任何效果。我在默认的 Jhispter 安全配置中添加了以下内容:

        http
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .maximumSessions(1).maxSessionsPreventsLogin(true).sessionRegistry(sessionRegistry());

    @Bean
    public SessionRegistry sessionRegistry() 
        SessionRegistry sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() 
        return new HttpSessionEventPublisher();
    


我知道 Spring Security 需要一个在下面添加的 HttpSessionListener,而且我看到关于是否需要添加 sessionRegistry 的相互矛盾的报告。

根据我在春季文档中阅读的所有内容,这应该足以将每个用户的登录次数限制为 1,但是您仍然可以无限次登录。 Jhispter 文档没有进入最大会话,因此也没有多大帮助。

这是整个安全配置:

package com.sean.silly.config;

import com.sean.silly.security.*;
import com.sean.silly.security.jwt.*;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.web.filter.CorsFilter;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    private final TokenProvider tokenProvider;

    private final CorsFilter corsFilter;
    private final SecurityProblemSupport problemSupport;

    public SecurityConfiguration(TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) 
        this.tokenProvider = tokenProvider;
        this.corsFilter = corsFilter;
        this.problemSupport = problemSupport;
    

    @Bean
    public PasswordEncoder passwordEncoder() 
        return new BCryptPasswordEncoder();
    

    @Override
    public void configure(WebSecurity web) 
        web.ignoring()
            .antMatchers(HttpMethod.OPTIONS, "/**")
            .antMatchers("/swagger-ui/index.html")
            .antMatchers("/test/**");
    

    @Override
    public void configure(HttpSecurity http) throws Exception 
        // @formatter:off
        http
            .csrf()
            .disable()
            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(problemSupport)
            .accessDeniedHandler(problemSupport)
        .and()
            .headers()
            .contentSecurityPolicy("default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:")
        .and()
            .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
        .and()
            .featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
        .and()
            .frameOptions()
            .deny()
        .and()
            .authorizeRequests()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers("/api/account/reset-password/init").permitAll()
            .antMatchers("/api/account/reset-password/finish").permitAll()
            .antMatchers("/api/**").authenticated()
            .antMatchers("/management/health").permitAll()
            .antMatchers("/management/info").permitAll()
            .antMatchers("/management/prometheus").permitAll()
            .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
        .and()
            .httpBasic()
        .and()
            .apply(securityConfigurerAdapter());
        // @formatter:on

        http
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .maximumSessions(1).maxSessionsPreventsLogin(true).sessionRegistry(sessionRegistry());
    

    private JWTConfigurer securityConfigurerAdapter() 
        return new JWTConfigurer(tokenProvider);
    

    @Bean
    public SessionRegistry sessionRegistry() 
        SessionRegistry sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() 
        return new HttpSessionEventPublisher();
    




【问题讨论】:

【参考方案1】:

jhipster的security approach中JWT和Sessions(用于安全/登录)互斥(不可混用)

JWT 是一种无状态身份验证机制,因此防止或禁用多次登录需要额外的工作。看到类似问题here和here

配置会话不会对此产生影响。

此外,除了 JWT 问题,您的 http 会话配置在语法上是正确的,但在语义上似乎没有意义:

sessionCreationPolicy(SessionCreationPolicy.STATELESS) 说"spring will neither create nor use the http session" 实际上比您的用例的“从不”选项更错误。

因此,添加 maximumSessions(1)(或其他任何内容)似乎没有任何意义。

【讨论】:

谢谢,没有点击 JWT 实现是 Sessions 独有的。你提供给我的链接有我想要的工作!

以上是关于JHipster 限制用户会话不适用于默认 JWT 配置的主要内容,如果未能解决你的问题,请参考以下文章

Jhipster 使用电子邮件而不是用户名登录

扩展 Jhipster JWT (Spring) 单体应用程序以支持模拟

JWT 用于无状态 API,但会话控制用于安全性

Nodejs Express 用于 Web 应用程序 JWT,带有数据库或会话以验证用户身份

注销不适用于 Laravel JWT-auth

VaryByCustom 不适用于会话变量