Java 如何在Spring5控制器中声明性地使用JWT授权?

Java 如何在Spring5控制器中声明性地使用JWT授权?,java,spring-boot,spring-security,jwt,spring-security-oauth2,Java,Spring Boot,Spring Security,Jwt,Spring Security Oauth2,有一个简单的web服务,只有一个端点“GET/hello” 最好在控制器中以声明的方式描述JWT,以便从中提取关于发出请求的授权用户的一些数据 在Github上浏览一些开源项目时,我发现@AuthenticationPrincipal注释不知何故参与了这个过程。然而,我找到的所有教程都没有提到这种声明性方法——它们主要展示如何创建JWT,而不是如何处理JWT。 如果你能指出我错过的值得注意的例子,我将不胜感激 很明显,这个问题很小,并且与Spring安全性的基本功能有关,但我不能把这个难题放在一

有一个简单的web服务,只有一个端点
“GET/hello”

最好在控制器中以声明的方式描述JWT,以便从中提取关于发出请求的授权用户的一些数据

在Github上浏览一些开源项目时,我发现
@AuthenticationPrincipal
注释不知何故参与了这个过程。然而,我找到的所有教程都没有提到这种声明性方法——它们主要展示如何创建JWT,而不是如何处理JWT。
如果你能指出我错过的值得注意的例子,我将不胜感激

很明显,这个问题很小,并且与Spring安全性的基本功能有关,但我不能把这个难题放在一起

请帮助我找到一种正确(自然)的方法,将JWT传递到控制器并从中获取数据
您能分享一个带有依赖项的工作示例和一个小测试,展示如何在controller中使用JWT吗

SpringBoot 2.4.0

import org.springframework.   ???   .Jwt;
import org.springframework.security.core.annotation.AuthenticationPrincipal;


@RestController 
public class MyController {
 
    @GetMapping("hello")
    public Object getRequests(@AuthenticationPrincipal Jwt jwt) {
      
      String name = getPropertyFromJwt(jwt, "name");
      String id = getPropertyFromJwt(jwt, "id");
      
      return Map.of("name", name, "id", id);
    }
}

要成功进行身份验证,请求必须由
身份验证提供程序
进行身份验证。一旦成功进行身份验证,它将返回一个
身份验证
对象,该对象包含一个主体对象

@AuthenticationPrincipal
仅帮助访问此principle对象。但是,spring security没有提供一个
AuthenticationProvider
,它可以通过JWT即时验证,这意味着您必须自己实现。在自定义的
AuthenticationProvider
中,您验证JWT并解码感兴趣的属性,并创建一个保存这些属性的自定义主体对象,以便您可以通过
@AuthenticationPrincipal
访问它们


只要快速搜索一下,就会发现这可能会对你有所帮助。

深入研究后,我发现这个问题包括 三个:

  • 如何将JWT字符串解析为对象
  • 如何将对象传递到控制器方法中
  • SpingBoot中的标准/默认方法是什么
  • 以下是简短的答案:

  • 使用您喜欢的任何库将编码的JWT转换为对象。
    其中之一是

  • @AuthenticationPrincipal
    注释的参数可以是任何类型的
    X
    它来自于
    currentSecurityContext.getAuthorization().getPrincipal()
    其中
    currentSecurityContext
    的类型为
    org.springframework.security.core.context.SecurityContext

    在WebFlux配置中,它来自调用
    ServerSecurityContextRepository.load(…)
    对于每个请求(请参见下面的实现)

  • 我没能找到#3的答案,但我意识到了这一点 这方面有几个开源的特别实现(好的和坏的)。 毕竟,我最终实现了另一个,只是为了理解陷阱

  • 请找到一个最小工作项目示例

    重点是:

    • A.使用
      ServerSecurityContextRepository的实现进行配置

      @EnableWebFluxSecurity
      public class SecurityConfig {
      
        @Bean
        SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
          ServerSecurityContextRepository repo = createContextRepository();
      
          return http
                     .authorizeExchange(e -> e.anyExchange().authenticated())
                     .securityContextRepository(repo)
                     .build();
         }
      }
      
    • B.创建
      身份验证
      接口的实现和一个函数(或函数链)
      ServerWebExchange->Authentication
      ,该函数应应用于
      serversecuritycontextextrepository.load
      方法并插入
      SecurityContext
      (即
      SecurityContextImpl
      )每个服务器请求的名称

    • C.委托人可以是您选择的任何对象。从(B)中创建的实现方法的
      Authentication.getPrincipal()
      返回它


    您需要的一切都在这里:如果您想按原样读取JWT(在base64中),请将HttpServletRequest添加为方法参数:(public Object getRequests(,HttpServletRequest request))并调用request.getHeader(“授权”);然后,您将使用JWT directlyanother选项直接访问标头(使用@RequestHeader注释):@RoieBeck好的,我们将该标头作为字符串。接下来,如何解析它?提供了所有java框架的列表:),maven包就是一个例子,在github页面中搜索“decodeatoken”,它非常简单。每个库都有自己的方式来解码JWT,你也可以做Base64。自己解码JWT正文(JWT的第二部分也称为有效负载:),作为一个一般规则,我认为你需要在使用它之前更好地理解JWT…谢谢Ken Chan。我相信这个例子可以指引我正确的方向。一般来说,每个应用程序都应该从头开始实现自己的AuthenticationProvider,尽管auth的各个领域都是如此标准化,您不觉得奇怪吗。我希望在SpringBoot初学者中至少能看到这个“JWT关注点”的基本实现。在我看来,对于WebFlux来说,同样的东西会带来额外的麻烦。