web-dev-qa-db-de.com

Wie ordne ich das OAuth 2-Token dem UserDetails-Objekt auf einem Ressourcenserver zu?

Ich habe zwei separate Spring Boot-Anwendungen, eine als OAuth 2-Autorisierungsserver und die andere als Ressourcenserver. Ich verwende die RemoteTokenServices von Spring auf meinem Ressourcenserver, um Token vom Autorisierungsserver zu überprüfen. Jetzt versuche ich, geschützten Controller-Code in meiner Ressourcenserver-Anwendung zu definieren, bin mir jedoch nicht sicher, wie ich die Klasse UserDetails dem Authentifizierungsprinzip zuordnen kann, das über den OAuth 2-Mechanismus bereitgestellt wird.

Ich habe meinen Berechtigungsserver mit einer benutzerdefinierten TokenEnhancer eingerichtet, die dem Token weitere Details hinzufügt, sodass /oauth/check_token?token=<token> mit benutzerdefinierten Feldern zurückgegeben wird, die ich meinen Ressourcenserver-Controllern zuordnen möchte.

In einer eher monolithischen Konfiguration, in der der Autorisierungsserver auch der Ressourcenserver ist, kann ich Controllermethoden definieren, die den authentifizierten Principal folgendermaßen verwenden:

//User implements UserDetails
public Map<String, Object> getResource(@AuthenticationPrincipal User user) {
    //code that uses the user object
}

Dies scheint jedoch in einem verteilten Ansatz nicht so einfach zu funktionieren. Die Zuordnung schlägt fehl und der Parameter user ist am Ende ein Nullobjekt. Ich habe versucht, den folgenden Ansatz zu verwenden:

public Map<String, Object> getResource(Authentication authentication) {
    //code that uses the authentication object
}

Der obige Code ordnet die Authentifizierungsdetails zwar erfolgreich zu, bietet mir jedoch keine Möglichkeit, direkt auf die benutzerdefinierten Felder zuzugreifen, die ich über die zuvor erwähnte TokenEnhancer festgelegt habe. Ich kann in den Spring-Dokumenten anscheinend nichts dazu finden.

9
Psycho Punch

Um das Problem zu lösen, lassen Sie mich zunächst ein wenig architektonischen Hintergrund betrachten. Das UserDetails-Objekt, das automatisch durch den @AuthenticationPrincipal zugeordnet wird, stammt aus dem principal-Feld des aktiven Authentication-Objekts. Ein Resource Server-Controller hat Zugriff auf ein OAuth2Authencation-Objekt, bei dem es sich um eine spezialisierte Instanz von Authentication für das Spring OAuth2-Sicherheitsframework handelt, indem es einfach als Teil der Methodenparameter deklariert wird. 

public void controllerMethod(OAuth2Authentication authentication) {
    //controller definition
}

Wenn Sie dies wissen, wird das Problem nun verschoben, um sicherzustellen, dass die getPrincipal()-Methode im Authentication-Objekt eine Instanz meiner benutzerdefinierten UserDetails-Klasse ist. Die Variable RemoteTokenServices, die ich in der Ressourcenserveranwendung verwende, verwendet eine Instanz von AccessTokenConverter, um die vom Berechtigungsserver gesendeten Token-Details zu interpretieren. Standardmäßig wird DefaultAccessTokenConverter verwendet, wodurch der Authentifizierungsprinzipal nur als Benutzername festgelegt wird. Dies ist eine String. Dieser Konverter verwendet UserAuthenticationConverter, um die vom Autorisierungsserver kommenden Daten in eine Instanz von Authentication zu konvertieren. Das musste ich anpassen:

DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
tokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() {

    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        Authentication authentication = super.extractAuthentication(map);
        // User is my custom UserDetails class
        User user = new User();
        user.setSpecialKey(map.get("specialKey").toString());
        return new UsernamePasswordAuthenticationToken(user,
                authentication.getCredentials(), authentication.getAuthorities());
    }

});
tokenServices.setAccessTokenConverter(tokenConverter);

Mit all diesen Einstellungen funktioniert der @AuthenticationPrincipal-Mechanismus jetzt wie erwartet.

15
Psycho Punch

Haben Sie die Variable AuthenticationPrincipalArgumentResolver wie folgt aktiviert?

<mvc:annotation-driven>
        <mvc:argument-resolvers>
                <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
        </mvc:argument-resolvers>
</mvc:annotation-driven>

Und Sie müssen die UserDetails implementieren, um Ihren eigenen CustomerUser object zurückzugeben. Anschließend können Sie die Annotation verwenden, um den Principal direkt abzurufen.

0
chaoluo