web-dev-qa-db-fra.com

Extraire les informations utilisateur actuellement connecté à partir du jeton JWT à l'aide de Spring Security

J'ai implémenté l'authentification JWT et LDAP à l'aide de Spring Security Oauth2. Cela semble bien fonctionner et je peux me connecter avec mes informations d'identification LDAP.

Maintenant, il y a une exigence que j'ai besoin d'utiliser les informations utilisateur actuellement connecté pour enregistrer les détails dans la base de données - en particulier comme lorsque cet utilisateur ajoute/met à jour un nouvel enregistrement. J'ai essayé d'obtenir cela en utilisant la sécurité Spring en utilisant

SecurityContextHolder.getContext().getAuthentication().getDetails() 

mais il ne renvoie pas toutes ces informations que j'ai dans JWT. Il renvoie simplement l'IP distant, la valeur du jeton JWT et authentifié vrai. Il ne retourne même pas name ().

Je suis nouveau sur JWT, donc je ne sais pas si je dois l'extraire en lisant ce jeton et même comment nous pouvons y parvenir.

Tout pointeur sera apprécié.

Merci.

12
mayur tanna

La première chose que vous devez faire est de stocker les informations utilisateur dans le JWT lors de sa création, puis vous devez les extraire lors de leur utilisation. J'ai eu une situation similaire et je l'ai résolue en étendant à la fois TokenEnhancer et JwtAccessTokenConverter.


J'utilise le TokenEnhancer pour incorporer mon principal étendu de type CustomUserDetails à l'intérieur des informations supplémentaires JWT.

public class CustomAccessTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Authentication userAuthentication = authentication.getUserAuthentication();
        if (userAuthentication != null) {
            Object principal = authentication.getUserAuthentication().getPrincipal();
            if (principal instanceof CustomUserDetails) {
                Map<String, Object> additionalInfo = new HashMap<>();
                additionalInfo.put("userDetails", principal);
                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            }
        }
        return accessToken;
    }
}


Et puis extrayez manuellement le principal étendu lors de la construction de l'objet Authentication lors du traitement d'une demande authentifiée.

public class CustomJwtAccessTokenConverter extends JwtAccessTokenConverter {

    @Override
    public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
        OAuth2Authentication authentication = super.extractAuthentication(map);
        Authentication userAuthentication = authentication.getUserAuthentication();

        if (userAuthentication != null) {
            LinkedHashMap userDetails = (LinkedHashMap) map.get("userDetails");
            if (userDetails != null) {

                // build your principal here
                String localUserTableField = (String) userDetails.get("localUserTableField");
                CustomUserDetails extendedPrincipal = new CustomUserDetails(localUserTableField);

                Collection<? extends GrantedAuthority> authorities = userAuthentication.getAuthorities();

                userAuthentication = new UsernamePasswordAuthenticationToken(extendedPrincipal,
                        userAuthentication.getCredentials(), authorities);
            }
        }
        return new OAuth2Authentication(authentication.getOAuth2Request(), userAuthentication);
    }
}


et la configuration AuthorizationServer pour tout lier ensemble.

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        CustomJwtAccessTokenConverter accessTokenConverter = new CustomJwtAccessTokenConverter();
        accessTokenConverter.setSigningKey("a1b2c3d4e5f6g");
        return accessTokenConverter;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomAccessTokenEnhancer();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
        endpoints
                .tokenStore(tokenStore())
                .tokenEnhancer(tokenEnhancerChain)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.passwordEncoder(passwordEncoder());
        security.checkTokenAccess("isAuthenticated()");
    }
}


Je peux ensuite accéder à mon principal étendu dans mon contrôleur de ressources comme celui-ci

@RestController
public class SomeResourceController {

    @RequestMapping("/some-resource")
    public ResponseEntity<?> someResource(Authentication authentication) {
        CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
        return ResponseEntity.ok("woo hoo!");
    }

}

J'espère que cela t'aides!

10
zero01alpha

Dans votre service REST, ajoutez la classe OAuth2Authentication comme argument

@RequestMapping(value = "/{id}/products", method = RequestMethod.POST)
    public ResourceResponse<String> processProducts(OAuth2Authentication auth) {

Springboot mappera automatiquement les détails de l'utilisateur connecté à cet objet. Maintenant, vous pouvez faire ce qui suit pour accéder au nom d'utilisateur

auth.getPrincipal().toString()
2
Chids