简体   繁体   English

如何在springboot controller授权中使用自定义JWT声明?

[英]How do I use custom JWT claims in springboot controller authorization?

In Spring Boot I have a JWT token generated with Keycloak which has some custom claims:在 Spring Boot 中,我有一个使用 Keycloak 生成的 JWT 令牌,它有一些自定义声明:

{
  ...
  custom_claim:123
}

I can add an Authentication parameter in my rest controller and I can see this attribute but its in a deeply nested location principal.context.token.otherclaims[0] in a class called RefreshableKeycloakSecurityContext .我可以在我的 rest controller 中添加一个身份验证参数,我可以看到这个属性,但它位于 class 中一个深度嵌套的位置principal.context.token.otherclaims[0]中,称为RefreshableKeycloakSecurityContext What is the best way to use this claim in PreAuthorization ?PreAuthorization中使用此声明的最佳方法是什么? I think what I want is to compare the claim in the token with a path parameter and return an error if they don't match.我想我想要的是将令牌中的声明与路径参数进行比较,如果它们不匹配则返回错误。

@PreAuthorization("custom_claim=#my-path-parm")

Libraries to use and avoid使用和避免使用的库

You have an instance of RefreshableKeycloakSecurityContext in security context because you are using Keycloak adapters for Spring. You shouldn't: it is very deprecated and not even compatible with spring-boot 3.您在安全上下文中有一个RefreshableKeycloakSecurityContext实例,因为您正在为 Spring 使用 Keycloak 适配器。您不应该:它已被弃用,甚至与 spring-boot 3 不兼容。

Details for configuring security of a Spring app with spring-boot and Keycloak in this other answer在此其他答案中使用 spring-boot 和 Keycloak 配置 Spring 应用程序安全性的详细信息

How to compare path-variable with token claim如何比较路径变量与令牌声明

You can have the Authentication instance be "auto-magically" injected as controller parameter.您可以将Authentication实例“自动神奇地”注入为 controller 参数。 By default for resource-servers, you'll get a JwtAuthenticationToken with JWT decoder and BearerTokenAuthentication with introspection ("opaque" tokens).默认情况下,对于资源服务器,您将获得带有JwtAuthenticationToken解码器的BearerTokenAuthentication和带有内省(“不透明”令牌)的 BearerTokenAuthentication。

@RequestMapping("/{machin}")
@PreAuthorize("#machin eq #auth.tokenAttributes['yourclaim']") 
public SomeDto controllerMethod(@PathVariable("machin") String machin, AbstractOAuth2TokenAuthenticationToken<?> auth) {
   ...
}

Private claims access simplification私人索赔访问简化

In spring-security, claim-set is typed Map<String, Object> .在 spring-security 中,claim-set 的类型为Map<String, Object> Accessing claims value requires null checks and casting, which can make a lot of grunt code, specially for nested claims.访问 claims 值需要 null 次检查和转换,这会产生很多 grunt 代码,特别是对于嵌套的 claims。

I suggest you write a custom Authentication instance, using AbstractAuthenticationToken as base class, to wrap private claims parsing and casting (claim values are Object).我建议您编写一个自定义身份验证实例,使用AbstractAuthenticationToken作为基础 class,以包装私有声明解析和转换(声明值是对象)。 With spring-boot-starter-oauth2-resource-server you provide a jwtAuthenticationConverter for that:使用spring-boot-starter-oauth2-resource-server ,您可以为此提供一个jwtAuthenticationConverter

http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwt -> new YourAuthenticationImpl(jwt, authoritiesConverter.convert(jwt)));

You might also provide a custom DSL to make security expressions more readable and, more importantly, easier to maintain: expressions definition would be at a single place instead of being spread accross controllers methods.您还可以提供自定义 DSL 以使安全表达式更具可读性,更重要的是,更易于维护:表达式定义将在一个地方,而不是分散在控制器方法中。

I have written a set of 3 tutorials which end with expressions like:我写了一套 3 个教程,这些教程以如下表达式结尾:

@GetMapping("/on-behalf-of/{username}")
@PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")
public String getGreetingFor(@PathVariable("username") String username, ProxiesAuthentication auth) {
    return "Hi %s from %s!".formatted(username, auth.getName());
}

This tutorials will also teach you how to unit-test your security expressions, even with private claims and custom Authentication.本教程还将教您如何对安全表达式进行单元测试,即使使用私有声明和自定义身份验证也是如此。 The endpoint secured with preceeding expression is tested as follow:用前面的表达式保护的端点测试如下:

@Test
@ProxiesAuth(
        authorities = { "AUTHOR" },
        claims = @OpenIdClaims(preferredUsername = "Tonton Pirate"),
        proxies = { @Proxy(onBehalfOf = "ch4mpy", can = { "greet" }) })
void whenNotNiceWithProxyThenCanGreetFor() throws Exception {
    mockMvc.get("/greet/on-behalf-of/ch4mpy")
        .andExpect(status().isOk())
        .andExpect(content().string("Hi ch4mpy from Tonton Pirate!"));
}

@Test
@ProxiesAuth(
        authorities = { "AUTHOR", "NICE" },
        claims = @OpenIdClaims(preferredUsername = "Tonton Pirate"))
void whenNiceWithoutProxyThenCanGreetFor() throws Exception {
    mockMvc.get("/greet/on-behalf-of/ch4mpy")
        .andExpect(status().isOk())
        .andExpect(content().string("Hi ch4mpy from Tonton Pirate!"));
}

@Test
@ProxiesAuth(
        authorities = { "AUTHOR" },
        claims = @OpenIdClaims(preferredUsername = "Tonton Pirate"),
        proxies = { @Proxy(onBehalfOf = "jwacongne", can = { "greet" }) })
void whenNotNiceWithoutRequiredProxyThenForbiddenToGreetFor() throws Exception {
    mockMvc.get("/greet/on-behalf-of/greeted")
        .andExpect(status().isForbidden());
}

@Test
@ProxiesAuth(
        authorities = { "AUTHOR" },
        claims = @OpenIdClaims(preferredUsername = "Tonton Pirate"))
void whenHimselfThenCanGreetFor() throws Exception {
    mockMvc.get("/greet/on-behalf-of/Tonton Pirate")
        .andExpect(status().isOk())
        .andExpect(content().string("Hi Tonton Pirate from Tonton Pirate!"));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 spring-authorization-server 在 JWT 中创建自定义声明 - How to create custom claims in JWT using spring-authorization-server 如何在 Spring 5 controller 中声明性地使用 JWT 的授权? - How to declaratively use authorization with JWT in Spring 5 controller? 如何在@WebMvcTest 中模拟自定义 JWT 声明 - How to mock custom JWT claims in @WebMvcTest Spring 引导 - 如何对 @Service class 方法在使用 JWT 和自定义声明时使用 @PreAuthorize 进行单元测试 - Spring Boot - How to unit test @Service class methods that use @PreAuthorize when using JWT with custom claims 如何使用资源服务器中授权服务器中的jdbc令牌存储访问添加到令牌的自定义声明? - How can I access custom claims added to token using jdbc token store in authorization server in resource server? 如何正确使用@GetMapping (SpringBoot)? - How do I use @GetMapping properly (SpringBoot)? 如何生成带有一些自定义声明的JWT访问令牌? - How to generate a JWT access token with some custom claims in it? 如何让超链接与 SpringBoot 控制器配合使用? - How do I get hyperlinks to play well with SpringBoot controller? 如何使用自定义构建的 JWT 来保护我的 API _WITHOUT_ 使用 oauth2 - How do I use a custom built JWT to protect my API _WITHOUT_ using oauth2 SpringBoot JWT安全性如何 - SpringBoot JWT security how to
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM