Spring OAuth with JWT custom UserDetails - Set Principal inside JwtAccessTokenConverter

南楼画角 提交于 2020-01-30 01:28:02

问题


Some additional info is sent from OAuth Authorization Server that is needed inside a custom UserDetails class on Resource Server, and preferably inside SpringSecurity Principal.

Current approach is setting a username as Principal and adding additional info as an additional details of Authentication object like this.

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;
    }
}

The good thing about this approach is we can access custom UserDetails from anywhere inside the app. The bad thing is that Pricipal object is stuck on being only users username, and we need a lot more code to access custom UserDetails.

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

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

Is there a cleaner solution to use JwtAccessTokenConverter but still be able to set Principal as custom UserDetails instead of setting it to (useless) username and sending additional info as details of Authentication object?


回答1:


I can not say if this is the preferred solution, but after trying to solve the same thing myself, I ended up extending the DefaultUserAuthenticationConverter.

So you can do something like this

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
  DefaultAccessTokenConverter defaultConverter = new DefaultAccessTokenConverter();
  defaultConverter.setUserTokenConverter(new CustomUserAuthenticationConverter());

  JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter();
  converter.setAccessTokenConverter(defaultConverter);
  return converter;
}

Then the DefaultUserAuthenticationConverter is not very extendable since most methods and properties are private. But here is an example

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.
  }

}


来源:https://stackoverflow.com/questions/51240197/spring-oauth-with-jwt-custom-userdetails-set-principal-inside-jwtaccesstokenco

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!