带有JWT自定义UserDetails的Spring OAuth-在JwtAccessTokenConverter中设置主体

时间:2018-07-09 07:32:29

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

从OAuth授权服务器发送一些其他信息,这是Resource Server上的自定义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对象的详细信息?

1 个答案:

答案 0 :(得分:0)

我不能说这是否是首选的解决方案,但是我自己尝试解决相同的问题后,我最终扩展了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.
  }

}