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 使用情况,但我只找到有关如何为单个租户实现该功能的信息。
如果有人已经成功实施了这个特定或类似的案例,或者可以将我推向正确的方向,我将非常感激。 或者也许我的想法是完全错误的,那么请告诉我。
感谢 @ch4mp 的回答,我已经成功了。 >工作答案2f81169b6e349b73ee04675e5c522113,每个身份验证管理器都有自己的身份验证转换器和自己的权限转换器来处理源声明和您想要的前缀。浏览 my tutorials 或 official documentation 以获取示例和实施提示。 This other answer 也可以提供帮助(权限映射要求完全不同,但身份验证管理器解析器类似)。
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中文网其他相关文章!