php小編百草為您精心撰寫了一篇關於使用AAD和AWS Cognito保護Spring Boot REST API的Java問答文章。在這篇文章中,我們將探討如何利用這兩種身分驗證服務來保護不同端點,確保您的API安全可靠。跟隨我們的指引,學習如何在您的Spring Boot專案中實現身分驗證和授權,讓您的REST API更加強大且可靠。
問題內容
希望有人可以在這裡幫助我,因為我在任何地方都找不到任何關於此主題的資源。
我有一個 spring boot restapi,目前配置有兩種路由:1. 未經授權 2. 透過 aad/entra 的 bearer 授權
我的配置方法目前設定如下:
@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() ); }
它包裝在一個擴充 aadresourceserverwebsecurityconfigureradapter
的類別中。
透過以這種方式設定我們的 api,我們能夠以以下方式保護我們的路由:
@preauthorize("hasauthority('approle_appname.rolename')") @getmapping(value = "/some-method", produces = mediatype.application_json_value) public responseentity<list<string>> getstrings() { return responseentity.ok(...); }
我們的 api 現在應該進行擴展,以允許新型使用者使用授權端點。這些用戶由 aws cognito 管理。如何設定我的 websecurityconfigureradapter
以允許某些路徑未經授權,某些路徑透過 aad 進行保護,某些路徑透過 aws cognito 進行保護?
我似乎遇到的主要問題是 aadresourceserverwebsecurityconfigureradapter
以這樣的方式設定 jwt 驗證,它只適用於 microsoft 提供的 bearers。
理想情況下我想要這樣的東西:
@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() ); } } }
我發現的另一個問題是 aadresourceserverwebsecurityconfigureradapter
自動將 jwtclaimnames「roles」和「scp」的所有可能的前綴設為「scope_」和「approle_」。理想情況下,我希望 aad 和 aws cognito 的它們有所不同,以便我將“aad_scope_”、“aad_approle_”和“cognito_group_”作為前綴。
我找到了一些資料解釋如何為 spring boot 實現多租戶 jwt 驗證,但它們都僅使用 sql 資料庫實現基於密碼/用戶的身份驗證。
有沒有辦法基本上必須重新實現所有 aad 邏輯,以便我可以混合對 aws cognito 給出的 jwt 的驗證,或者有沒有辦法根據路由進行決定?
我已經知道您可以在 httpsecurity
上使用 oauth2resourceserver()
函數來配置 jwt 使用情況,但我只找到有關如何為單一租用戶實現該功能的資訊。
如果有人已經成功實施了這個特定或類似的案例,或者可以將我推向正確的方向,我將非常感激。 或者也許我的想法是完全錯誤的,那麼請告訴我。
使用工作解決方案更新(2024 年 1 月 25 日)
感謝 @ch4mp 的回答,我已經成功了。 >工作答案
現在我的實作已經高度簡化,如下:
應用程式.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
安全配置
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 { }
我的控制器現在看起來像這樣:
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!"); } }
建置.gradle
#implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' implementation 'com.c4-soft.springaddons:spring-addons-starter-oidc:7.3.5'
這不是 spring 的官方啟動器,而是 oss 實作:https://www.php.cn/link/49844ba129a1cbc3d964703fcdb756ba
如果我遇到任何其他問題,我會再次更新,但目前它正在工作。
解決方法
我將在這裡公開一個使用 my starter 的解決方案,因為它更容易。
如果您喜歡僅使用「官方」spring boot 啟動器建立安全配置,則必須使用iss
聲明提供自己的authenticationmanagerresolver<httpservletrequest></httpservletrequest>
,每個驗證管理器都有自己的身份驗證轉換器和自己的權限轉換器來處理來源聲明和您想要的前綴。瀏覽 my tutorials 或 official documentation 以取得範例和實作提示。 This other answer 也可以提供協助(權限對應要求完全不同,但驗證管理器解析器類似)。
使用 boot 3.2.2
和 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 { }
編輯以下 application.yaml
以放置您自己的發行者:
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/**
上面 path
的值是 json 路徑。您可以使用 jsonpath.com 等工具根據您自己的令牌有效負載(使用 jwt.io 等工具提取)測試路徑表達式。
是的,就這麼簡單。不,我沒有省略任何 yaml 屬性或 java 配置(如果您不相信我,只需在新專案中進行測試)。
示例控制器
@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" }
以上是使用 AAD 和 AWS Cognito 為不同端點保護 Spring Boot REST API的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。