php-Editor Baicao hat für Sie sorgfältig einen Java-Q&A-Artikel über die Verwendung von AAD und AWS Cognito zum Schutz der Spring Boot REST API geschrieben. In diesem Artikel erfahren Sie, wie Sie diese beiden Authentifizierungsdienste nutzen können, um verschiedene Endpunkte zu schützen und sicherzustellen, dass Ihre API sicher und geschützt ist. Folgen Sie unserem Leitfaden und erfahren Sie, wie Sie Authentifizierung und Autorisierung in Ihrem Spring Boot-Projekt implementieren, um Ihre REST-API leistungsfähiger und zuverlässiger zu machen.
Hoffentlich kann mir hier jemand helfen, da ich nirgendwo Ressourcen zu diesem Thema finden kann.
Ich habe ein Spring-Boot-Restapi und die aktuelle Konfiguration hat zwei Routen: 1. Nicht autorisiert 2. Autorisiert durch den Träger von aad/entra
Meine Konfigurationsmethode ist derzeit wie folgt eingerichtet:
@override protected void configure(httpsecurity http) throws exception { super.configure(http); http.csrf().disable(); http.authorizerequests(requests -> requests .antmatchers(httpmethod.options, "/**/**").permitall() .antmatchers("/api/protected/**").fullyauthenticated() .anyrequest().permitall() ); }
Es ist in eine Klasse verpackt, die aadresourceserverwebsecurityconfigureradapter
erweitert.
Durch die Konfiguration unserer API auf diese Weise können wir unsere Routen wie folgt sichern:
@preauthorize("hasauthority('approle_appname.rolename')") @getmapping(value = "/some-method", produces = mediatype.application_json_value) public responseentity<list<string>> getstrings() { return responseentity.ok(...); }
Unsere API sollte nun erweitert werden, um neuen Benutzertypen die Nutzung des Autorisierungsendpunkts zu ermöglichen. Diese Benutzer werden von aws cognito verwaltet. Wie richte ich mein websecurityconfigureradapter
so ein, dass einige Pfade nicht autorisiert sind, einige Pfade über AAD geschützt werden und einige Pfade über aws cognito geschützt werden?
Das Hauptproblem, das ich zu haben scheint, besteht darin, aadresourceserverwebsecurityconfigureradapter
die JWT-Validierung so zu konfigurieren, dass sie nur mit von Microsoft bereitgestellten Trägern funktioniert.
Idealerweise hätte ich gerne so etwas:
@configuration @enablewebsecurity @enableglobalmethodsecurity(prepostenabled = true) public class securityconfig extends websecurityconfigureradapter { @configuration @order(1) public static class azureadsecurityconfig extends aadresourceserverwebsecurityconfigureradapter { @override protected void configure(httpsecurity http) throws exception { http.authorizerequests(requests -> requests .antmatchers("/api/aad/**").fullyauthenticated() ); http.oauth2resourceserver().jwt([utilize aad jwt validation]); } } @configuration @order(2) public static class awscognitosecurityconfig extends websecurityconfigureradapter { @override protected void configure(httpsecurity http) throws exception { http.authorizerequests(requests -> requests .antmatchers("/api/cognito/**").fullyauthenticated() ); http.oauth2resourceserver().jwt([utilize aws cognito jwt validation]); } } @configuration @order(3) public static class defaultsecurityconfig extends websecurityconfigureradapter { @override protected void configure(httpsecurity http) throws exception { http.csrf().disable(); http.authorizerequests(requests -> requests .antmatchers(httpmethod.options, "/**/**").permitall() .anyrequest().permitall() ); } } }
Ein weiteres Problem, das ich gefunden habe, war aadresourceserverwebsecurityconfigureradapter
das automatische Setzen aller möglichen Präfixe für jwtclaimnames „roles“ und „scp“ auf „scope_“ und „approle_“. Idealerweise möchte ich, dass sie für aad und aws cognito unterschiedlich sind, sodass ich „aad_scope_“, „aad_approle_“ und „cognito_group_“ voranstelle.
Ich habe einige Informationen gefunden, die erklären, wie man die mandantenfähige JWT-Authentifizierung für Spring Boot implementiert, aber alle verwenden nur SQL-Datenbank, um die passwort-/benutzerbasierte Authentifizierung zu implementieren.
Gibt es eine Möglichkeit, bei der ich grundsätzlich die gesamte AAD-Logik neu implementieren muss, damit ich die von aws cognito bereitgestellte Validierung des JWT einbinden kann, oder gibt es eine Möglichkeit, die Entscheidung basierend auf dem Routing zu treffen?
Ich weiß bereits, dass Sie die JWT-Nutzung in der Funktion httpsecurity
上使用 oauth2resourceserver()
konfigurieren können, aber ich habe nur Informationen zur Implementierung dieser Funktionalität für einen einzelnen Mandanten gefunden.
Wenn jemand diesen konkreten oder ähnlichen Fall erfolgreich umgesetzt hat oder mich in die richtige Richtung drängen kann, wäre ich sehr dankbar. Oder vielleicht ist meine Idee völlig falsch, also sagen Sie es mir bitte.
Danke an @ch4mp für die Antwort, es ist mir gelungen. >Arbeitsantworten<
Meine Implementierung ist jetzt stark vereinfacht und sieht so aus:
application.yml
com: c4-soft: springaddons: oidc: ops: - iss: https://cognito-idp.<region>.amazonaws.com/<cognito-pool> authorities: - path: $.cognito:groups prefix: cognito_group_ - iss: https://sts.windows.net/<entra objectid>/ authorities: - path: $.roles.* prefix: aad_approle_ - path: $.scp prefix: aad_scope_ aud: <enterprise application id> resource-server: permit-all: - /api/route/noauth
Sicherheitskonfiguration
package some.package; import org.springframework.context.annotation.configuration; import org.springframework.security.config.annotation.method.configuration.enablemethodsecurity; import org.springframework.security.config.annotation.web.configuration.enablewebsecurity; @enablewebsecurity @enablemethodsecurity @configuration public class securityconfig { }
Mein Controller sieht jetzt so aus:
package some.package; import org.springframework.http.responseentity; import org.springframework.security.access.prepost.preauthorize; import org.springframework.security.core.context.securitycontextholder; import org.springframework.security.oauth2.jwt.jwt; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; @restcontroller @requestmapping("/api/route") public class jwttestcontroller { @getmapping("/aadauth") @preauthorize("hasauthority('aad_approle_grantedapprole.xxx')") public responseentity<string> aadauthrole() { jwt jwt = (jwt) securitycontextholder.getcontext().getauthentication().getprincipal(); return responseentity.ok(jwt.getclaims().tostring()); } @getmapping("/aadauth") @preauthorize("hasauthority('aad_scope_grantedscope.xxx')") public responseentity<string> aadauthscope() { jwt jwt = (jwt) securitycontextholder.getcontext().getauthentication().getprincipal(); return responseentity.ok(jwt.getclaims().tostring()); } @preauthorize("hasauthority('cognito_group_somegroup')") @getmapping("/cognitoauth") public responseentity<string> cognitoauth() { jwt jwt = (jwt) securitycontextholder.getcontext().getauthentication().getprincipal(); return responseentity.ok(jwt.getclaims().tostring()); } @getmapping("/noauth") public responseentity<string> noauth() { return responseentity.ok("hello world!"); } }
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' implementation 'com.c4-soft.springaddons:spring-addons-starter-oidc:7.3.5'
Dies ist nicht der offizielle Launcher von Spring, sondern die Oss-Implementierung: https://www.php.cn/link/49844ba129a1cbc3d964703fcdb756ba
Ich werde es erneut aktualisieren, wenn ich auf andere Probleme stoße, aber im Moment funktioniert es.
Ich werde hier eine Lösung mit meinem Starter vorstellen, weil es einfacher ist.
Wenn Sie zum Erstellen Ihrer Sicherheitskonfiguration lieber nur den „offiziellen“ Spring Boot Launcher verwenden möchten, müssen Sie iss
声明提供自己的 authenticationmanagerresolver<httpservletrequest>
verwenden. Jeder Authentifizierungsmanager verfügt über einen eigenen Authentifizierungskonverter und einen eigenen Berechtigungskonverter, um die Quellansprüche zu verarbeiten, und Sie möchten das erforderliche Präfix. Durchsuchen Sie meine Tutorials oder offizielle Dokumentation nach Beispielen und Implementierungstipps. Diese andere Antwort kann ebenfalls hilfreich sein (die Anforderungen für die Berechtigungszuordnung sind völlig unterschiedlich, aber der Authentifizierungsmanager-Resolver ist ähnlich).
3.2.2
und Spring-Addons<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>3.2.2</version> <relativepath/> <!-- lookup parent from repository --> </parent> <groupid>com.c4-soft.demo</groupid> <artifactid>multi-tenant-resource-server</artifactid> <version>0.0.1-snapshot</version> <properties> <java.version>21</java.version> <spring-addons.version>7.3.5</spring-addons.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-oauth2-resource-server</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>com.c4-soft.springaddons</groupid> <artifactid>spring-addons-starter-oidc</artifactid> <version>${spring-addons.version}</version> </dependency> <dependency> <groupid>com.c4-soft.springaddons</groupid> <artifactid>spring-addons-starter-oidc-test</artifactid> <version>${spring-addons.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build> </project>
@configuration @enablemethodsecurity public class securityconf { }
Bearbeiten Sie Folgendes application.yaml
, um Ihren eigenen Herausgeber zu platzieren:
com: c4-soft: springaddons: oidc: ops: - iss: https://cognito-idp.us-west-2.amazonaws.com/us-west-2_rzhmglwjl authorities: - path: $.cognito:groups prefix: cognito_group_ - iss: https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/ authorities: - path: $.approles.*.displayname prefix: aad_approle_ - path: $.scope prefix: aad_scope_ resourceserver: # spring-addons whitelist is for permitall() (rather than isauthenticated()) # which is probably much safer permit-all: - /actuator/health/readiness - /actuator/health/liveness - /v3/api-docs/** - /api/public/**
Der Wert von path
oben ist der JSON-Pfad. Sie können Tools wie jsonpath.com verwenden, um Pfadausdrücke anhand Ihrer eigenen Token-Nutzlast zu testen (extrahiert mit Tools wie jwt.io).
Ja, so einfach ist das. Nein, ich habe keine Yaml-Eigenschaften oder Java-Konfiguration ausgelassen (wenn Sie mir nicht glauben, testen Sie es einfach in einem neuen Projekt).
@restcontroller public class greetcontroller { @getmapping("/greet") @preauthorize("isauthenticated()") public string getgreet(authentication auth) { return "hello %s! you are granted with %s.".formatted(auth.getname(), auth.getauthorities()); } @getmapping(value = "/strings") @preauthorize("hasanyauthority('aad_approle_admin', 'cognito_group_admin')") public list<string> getstrings() { return list.of("protected", "strings"); } }
@webmvctest(controllers = greetcontroller.class) @autoconfigureaddonswebmvcresourceserversecurity @import(securityconf.class) class greetcontrollertest { @autowired mockmvcsupport api; @test @withanonymoususer void givenuserisanonymous_whengetgreet_thenunauthorized() throws unsupportedencodingexception, exception { api.get("/greet").andexpect(status().isunauthorized()); } @test @withjwt("aad_admin.json") void givenuserisaadadmin_whengetgreet_thenok() throws unsupportedencodingexception, exception { final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring(); assertequals( "hello aad-admin! you are granted with [aad_approle_msiam_access, aad_approle_admin, aad_scope_openid, aad_scope_profile, aad_scope_machin:truc].", actual); } @test @withjwt("cognito_admin.json") void givenuseriscognitoadmin_whengetgreet_thenok() throws unsupportedencodingexception, exception { final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring(); assertequals("hello amazon-cognito-admin! you are granted with [cognito_group_admin, cognito_group_machin:truc].", actual); } @test @withjwt("aad_machin-truc.json") void givenuserisaadmachintruc_whengetgreet_thenok() throws unsupportedencodingexception, exception { final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring(); assertequals("hello aad-user! you are granted with [aad_approle_msiam_access, aad_scope_openid, aad_scope_profile, aad_scope_machin:truc].", actual); } @test @withjwt("cognito_machin-truc.json") void givenuseriscognitomachintruc_whengetgreet_thenok() throws unsupportedencodingexception, exception { final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring(); assertequals("hello amazon-cognito-user! you are granted with [cognito_group_machin:truc].", actual); } @test @withanonymoususer void givenuserisanonymous_whengetstrings_thenunauthorized() throws unsupportedencodingexception, exception { api.get("/strings").andexpect(status().isunauthorized()); } @test @withjwt("aad_admin.json") void givenuserisaadadmin_whengetstrings_thenok() throws unsupportedencodingexception, exception { final var actual = api.get("/strings").andexpect(status().isok()).andreturn().getresponse().getcontentasstring(); assertequals("[\"protected\",\"strings\"]", actual); } @test @withjwt("cognito_admin.json") void givenuseriscognitoadmin_whengetstrings_thenok() throws unsupportedencodingexception, exception { final var actual = api.get("/strings").andexpect(status().isok()).andreturn().getresponse().getcontentasstring(); assertequals("[\"protected\",\"strings\"]", actual); } @test @withjwt("aad_machin-truc.json") void givenuserisaadmachintruc_whengetstrings_thenforbidden() throws unsupportedencodingexception, exception { api.get("/strings").andexpect(status().isforbidden()); } @test @withjwt("cognito_machin-truc.json") void givenuseriscognitomachintruc_whengetstrings_thenforbidden() throws unsupportedencodingexception, exception { api.get("/strings").andexpect(status().isforbidden()); } }
使用此测试资源:
aad_admin.json
{ "sub": "aad-admin", "iss": "https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/", "approles": [ { "allowedmembertypes": [ "user" ], "description": "msiam_access", "displayname": "msiam_access", "id": "ef7437e6-4f94-4a0a-a110-a439eb2aa8f7", "isenabled": true, "origin": "application", "value": null }, { "allowedmembertypes": [ "user" ], "description": "administrators only", "displayname": "admin", "id": "4f8f8640-f081-492d-97a0-caf24e9bc134", "isenabled": true, "origin": "serviceprincipal", "value": "administrator" } ], "scope": "openid profile machin:truc" }
aad_machin-truc.json
{ "sub": "aad-user", "iss": "https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/", "approles": [ { "allowedmembertypes": [ "user" ], "description": "msiam_access", "displayname": "msiam_access", "id": "ef7437e6-4f94-4a0a-a110-a439eb2aa8f7", "isenabled": true, "origin": "application", "value": null } ], "scope": "openid profile machin:truc" }
cognito_admin.json
{ "sub": "amazon-cognito-admin", "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_rzhmglwjl", "cognito:groups": ["admin", "machin:truc"], "scope": "openid profile cog:scope" }
cognito_machin-truc.json
{ "sub": "amazon-cognito-user", "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_RzhmgLwjl", "cognito:groups": ["machin:truc"], "scope": "openid profile cog:scope" }
Das obige ist der detaillierte Inhalt vonSichern der Spring Boot REST API für verschiedene Endpunkte mithilfe von AAD und AWS Cognito. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!