Spring Security 多个登录用户失败

Posted

技术标签:

【中文标题】Spring Security 多个登录用户失败【英文标题】:Spring Security multiple logged users fail 【发布时间】:2017-04-02 09:09:36 【问题描述】:

我正在使用 Spring、Spring Security 和 Hibernate 制作一个基本的井字游戏项目。应用程序可以为数据库中的每个登录用户保存游戏,并允许我们随时加载它。这不是问题,但在涉及多线程时会出现。当我在单个浏览器窗口中运行单个应用程序时,一切正常。但是当我打开另一个窗口时,两个玩家正在玩同一个游戏。

我知道这可能是由 Spring 创建的 bean 单例引起的,但我确信它不是。为了检查当前登录的用户,我做了一个方法来让他从 SecurityContextHolder

private User getUserFromSpringContext() 
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String name = authentication.getName();
    System.out.println("Currently logged users = " + name);
    return userService.findUserByUsername(name);

当多个用户登录时,该方法只打印其中一个用户的名称。我不知道为什么。以下是我的安全配置和 userDetails 类的一些重要代码行:

安全配置:

@Autowired
UserDetailsService userDetailsService;

@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder builder) throws Exception 
    builder.userDetailsService(userDetailsService);
    builder.authenticationProvider(authenticationProvider());


@Bean
public DaoAuthenticationProvider authenticationProvider() 
    DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
    auth.setUserDetailsService(userDetailsService);
    return auth;

自定义用户详情服务

@Autowired
private UserService userService;

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
    User user = userService.findUserByUsername(username);
    if (user == null) 
        throw new UsernameNotFoundException("Username not found");
    
    return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), true, true, true, true, getAuthoriries(user));


public void setUserService(UserService userService) 
    this.userService = userService;


private List<GrantedAuthority> getAuthoriries(User user) 
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority(user.getRole().getRole()));
    return authorities;

有人知道这个问题的原因吗?

在测试期间,我遇到了另一个问题。当我单击 Logout 时,所有用户都已注销。我在这里发布了我的 Spring 安全配置的其余部分。

 @Override
protected void configure(HttpSecurity http) throws Exception 
    http.authorizeRequests()
            .antMatchers("/start", "/", "/login", "/registry","/success","/new").permitAll()
            .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
            .antMatchers("/**").access("hasAnyRole('ROLE_USER','ROLE_ADMIN')")
            .and().formLogin().loginPage("/login").defaultSuccessUrl("/user")
            .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .and().csrf()
            .and().exceptionHandling().accessDeniedPage("/access_denied");

可能是什么问题?

【问题讨论】:

假设它以我认为的方式工作,您是否断言(但是)当用户登录时,他们的条目是在您的数据库中创建的?也许它只适用于第一个用户? 我编辑了帖子,因为我发现了另一个问题。 定义打开一个新窗口?如果您从现有浏览器(不是新浏览器)中按 CTRL+T 或 CTRL+N。会话状态、缓存和 cookie 将被复制。您实际上不是在玩多个玩家,而是在多个浏览器窗口中玩单个用户。我会说它可以正常工作,而您只是在以错误的方式对其进行测试。 只有当我打开 Chrome 和 Edge 等两种不同的浏览器时,我的应用才能正常运行。那么这是否意味着一切都很好,但我应该始终在多个浏览器中运行它? 【参考方案1】:

SecurityContextHolder 让您可以访问与 当前线程 关联的安全上下文,因此只有 当前 用户 - 其请求触发了对 getAuthentication() 的调用的用户,所以它的行为正是它应有的方式。

另一方面,如果您想要所有活动会话(即所有登录用户),您应该注入 SessionRegistry 并在其上调用 sessionRegistry.getAllPrincipals()

详情已经给here了。

【讨论】:

以上是关于Spring Security 多个登录用户失败的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security - 用户身份验证有时会失败并且用户被重定向到登录页面

Spring Security---多次登录失败账户锁定详解

Spring Security:如果身份验证失败,则重定向到登录页面

spring-security 个性化用户认证流程——自定义登录成功/失败的处理

Grails Spring Security登录失败未重定向到登录视图

为什么Spring Security看不见登录失败或者注销的提示