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.
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!
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()