【问题标题】:Spring OAuth with JWT custom UserDetails - Set Principal inside JwtAccessTokenConverter带有 JWT 自定义 UserDetails 的 Spring OAuth - 在 JwtAccessTokenConverter 中设置主体
【发布时间】:2018-12-16 19:43:33
【问题描述】:

从 OAuth 授权服务器发送一些额外的信息,这些信息需要在资源服务器上的自定义 UserDetails 类中,最好是在 SpringSecurity Principal 中。

当前的方法是将用户名设置为 Principal 并添加附加信息作为 Authentication 对象的附加详细信息,如下所示。

public class CustomAccessTokenConverter extends JwtAccessTokenConverter{

    @Override
    public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
        OAuth2Authentication authentication = super.extractAuthentication(claims);

        CustomUserDetails userDetails = new CustomUserDetails ();
        userDetails.setUserId(((Integer)claims.get("id")).longValue());
        userDetails.setName((String) claims.get("name"));
        userDetails.setLastName((String) claims.get("lastName"));

        authentication.setDetails(userDetails);

        return authentication;
    }
}

这种方法的好处是我们可以从应用程序内的任何位置访问自定义 UserDetails。坏事是 Pricipal 对象被困在只是用户的用户名上,我们需要更多的代码来访问自定义的 UserDetails。

// preferable way   
(UserAuthDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

// current solution
(UserAuthDetails) ((OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails()).getDecodedDetails();

是否有更简洁的解决方案来使用JwtAccessTokenConverter,但仍然能够将 Principal 设置为自定义 UserDetails,而不是将其设置为(无用的)用户名并将附加信息作为 Authentication 对象的详细信息发送?

【问题讨论】:

    标签: spring-security oauth jwt spring-security-oauth2


    【解决方案1】:

    我不能说这是否是首选解决方案,但在尝试自己解决同样的问题后,我最终扩展了DefaultUserAuthenticationConverter

    所以你可以做这样的事情

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
      DefaultAccessTokenConverter defaultConverter = new DefaultAccessTokenConverter();
      defaultConverter.setUserTokenConverter(new CustomUserAuthenticationConverter());
    
      JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter();
      converter.setAccessTokenConverter(defaultConverter);
      return converter;
    }
    

    那么 DefaultUserAuthenticationConverter 不是很可扩展,因为大多数方法和属性都是私有的。但这里有一个例子

    public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
    
      private static final String CUST_PROP = "custProp";
    
      @Override
      public Authentication extractAuthentication(Map<String, ?> map) {
        if (map.containsKey(USERNAME) && map.containsKey(CUST_PROP)) {
          String username = (String) map.get(USERNAME);
          String custProp = (String) map.get(CUST_PROP);
    
          CustomPrincipal principal = new CustomPrincipal();
          pricipal.setUsername(username);
          pricipal.setCustomProp(custProp);
    
          Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
          return new UsernamePasswordAuthenticationToken(user, "N/A", authorities);
        }
        return null;
      }
    
      private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
        //Copy this method from DefaultUserAuthenticationConverter or create your own.
      }
    
    }
    

    【讨论】:

    • 有趣的方式,我已经解决了这种方式,而不是在静态方法中包装 getter,所以我们在我们的应用程序周围得到了干净的代码,但这是一个很酷的建议,我希望它对同样的人有所帮助问题:)
    • 您是否发现extractAuthentication 方法被调用了两次?
    猜你喜欢
    • 2023-04-08
    • 2019-08-19
    • 2015-05-14
    • 2012-01-29
    • 1970-01-01
    • 2020-03-11
    • 2019-08-06
    • 2015-10-16
    • 2013-02-18
    相关资源
    最近更新 更多