【问题标题】:spring security oauth2 + switch user filterspring security oauth2 + 切换用户过滤器
【发布时间】:2016-12-04 22:53:56
【问题描述】:

我想在我的 spring-boot 应用程序中设置 SwitchUserFilter,该应用程序实现了 spring-security-oauth2。我已经在我的 WebSecurityConfiguration 中设置了这个过滤器,它扩展了 WebSecurityConfigurerAdapter。

登录后,我获得了我的令牌,一个不记名令牌,并使用配置的端点切换用户。

我在 IDE 中使用调试代码跟踪代码,显然 SecurityContextHolder 已更新并注入了新的目标用户。

但是,当请求被重定向到目标 URL(此过滤器的一个属性)时,SecurityContextHolder 将旧用户返回给我,而不是我请求的内容。

我检查了 OAuth2AuthenticationProcessingFilter 并且从请求中提取的令牌返回相同的不记名令牌,并以此构建用户详细信息并将其注入 SecurityContextHolder em>。

有什么方法可以通过 oauth2 方法使用这种过滤器吗?

【问题讨论】:

  • 你得到正确答案了吗?请分享?

标签: spring spring-security spring-security-oauth2


【解决方案1】:

问题是您需要创建一个包含新目标用户信息的新令牌。这个新令牌必须发送回客户端,因此对于未来的请求,将使用新的目标用户令牌。在我们的例子中,令牌被持久化在服务器端(使用 JDBCTokenStore),但它也可以在完全服务器端的无状态环境(JWT-Token)中工作。

我们的环境是一个带有 Angular 1.2 客户端的 spring-boot/jhipster 应用程序。

创建新令牌:

@Inject
private UserDetailsService userDetailsService;

@Inject
private AuthorizationServerTokenServices tokenService;

@Inject
private ClientDetailsService clientDetailsService;


   public OAuth2AccessToken createImpersonationAccessToken(String login) {
       UserDetails userDetails = userDetailsService.loadUserByUsername(login);
       log.info("Switching current user to {}", login);

       Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
       List<GrantedAuthority> impersonationAuthorities = new ArrayList<>(authorities);
       Authentication source = SecurityContextHolder.getContext().getAuthentication();
       // add current user authentication (to switch back from impersonation):
       SwitchUserGrantedAuthority switchUserAuthority = 
               new SwitchUserGrantedAuthority(AuthoritiesConstants.IMPERSONATION, source);
       impersonationAuthorities.add(switchUserAuthority);
                   UserDetails newUserDetails = 
               org.springframework.security.core.userdetails.User
               .withUsername(login)
               .authorities(impersonationAuthorities)
               .password("justinventedhere")
               .build();
                           Authentication userPasswordAuthentiation = 
               new UsernamePasswordAuthenticationToken(newUserDetails, null, impersonationAuthorities);

       Map<String, String> parameters = new HashMap<>();        
       ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
                   OAuth2Request oauthRequest = new OAuth2Request(parameters, client.getClientId(), client.getAuthorities(), true, 
               client.getScope(), client.getResourceIds(), null, null, null);
       OAuth2Authentication authentication = new OAuth2Authentication(oauthRequest, userPasswordAuthentiation);
       OAuth2AccessToken createAccessToken = tokenService.createAccessToken(authentication);
                   return createAccessToken;
   }

这个新令牌被返回给客户端(在我们的例子中是一个 Angular 1.2 应用程序),该客户端将令牌存储在其本地存储中(用于下一个请求)。然后应用程序需要重新加载(更新目标用户的最简单方法):

vm.switchToClient = function (client) {
    vm.switchingUser = true;
    UserService.switchToClient(client, function(response) {
                var expiredAt = new Date();
                $localStorage.authenticationToken = response;
                window.location.href='#/';
                window.location.reload()
            });
}

【讨论】:

  • 请分享完整信息。
【解决方案2】:

您可以注入自己的 AuthenticationManager 并覆盖该行为

private class AuthenticationManager extends OAuth2AuthenticationManager {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication();
        if (currentAuthentication instanceof UsernamePasswordAuthenticationToken) {
            for (GrantedAuthority ga : currentAuthentication.getAuthorities()) {
                if (ga instanceof SwitchUserGrantedAuthority) {
                    SwitchUserGrantedAuthority switchedFrom = (SwitchUserGrantedAuthority) ga;
                    Authentication switchedFromSource = switchedFrom.getSource();
                    for (GrantedAuthority sf : switchedFromSource.getAuthorities()) {
                        String authority = sf.getAuthority();
                        if (switchUserAuthority.equals(authority)) {
                            return currentAuthentication;
                        }
                    }
                    break;
                }
            }
        }
        return super.authenticate(authentication);
    }

【讨论】:

    猜你喜欢
    • 2018-09-20
    • 2017-07-06
    • 2020-02-08
    • 2012-10-22
    • 2019-04-06
    • 1970-01-01
    • 2019-09-25
    • 2013-06-20
    • 2016-04-30
    相关资源
    最近更新 更多