在 Spring Boot 中从 jwt 获取附加属性

Posted

技术标签:

【中文标题】在 Spring Boot 中从 jwt 获取附加属性【英文标题】:get additional attributes from jwt in spring boot 【发布时间】:2020-02-14 08:59:25 【问题描述】:

我正在开发一个受 keycloak 保护的 Spring Boot 服务,它接受 jwt 不记名令牌进行身份验证。

我还配置了 swagger 并将其注册为公共客户端,因此当我从 swagger-ui 发出请求时,keycloak 会生成一个 JWT 令牌,然后在向 api 发出请求时,swagger 会使用该令牌进行身份验证。

我还为用户信息创建了 2 个额外的私有映射器。现在我想在我的 spring 控制器中获取这两个属性。

下面是我的示例代码。 我对 spring security 和各种做事方式(spring security / oauth2 / keycloak 等)感到有点迷茫,所以对解决方案的一些解释将不胜感激。

pom.xml

<!-- spring security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- spring security test -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- KeyCloak -->
        <!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-spring-boot-2-starter -->
        <!-- https://***.com/questions/50243088/keycloak-4-0-0-beta-2-with-spring-boot-2 -->      <!---->
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-2-starter</artifactId>
            <version>4.0.0.Final</version>
        </dependency>

Spring 安全配置

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends KeycloakWebSecurityConfigurerAdapter  

    @Autowired
    public void configureGlobal(
      AuthenticationManagerBuilder auth) throws Exception 

        KeycloakAuthenticationProvider keycloakAuthenticationProvider
         = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
          new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() 
        return new KeycloakSpringBootConfigResolver();
    

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() 
        return new RegisterSessionAuthenticationStrategy(
          new SessionRegistryImpl());
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        super.configure(http);
        http.authorizeRequests()
          .antMatchers("/test*")
          .hasRole("user")
          .anyRequest()
          .permitAll();
    




示例控制器

    @RequestMapping(value = "HelloWorld1", method = RequestMethod.GET)
    @ApiOperation(value = "HelloWorld1", produces = "application/json")
    @ResponseBody
    public String HelloWorld1(Principal principal) 
//I'd like something like this to work:
//String attr = principal.getAttribute("attribute1");
//
        System.out.println(principal.getName());
        RestTemplate restTemplate = new RestTemplate();
        String text = restTemplate.getForObject(
            "http://localhost:8080/test/test/HelloWorld", String.class);
        return "Hello " + principal.getName() + " " +  "it works! \n " + text;
    

【问题讨论】:

你能解决你的目的吗? 我不明白你的问题。我没有解决我的问题...我现在只使用 JWT 进行身份验证 你实现了自定义的AuthenticationManager吗? 我不确定.. 我实现了 AuthenticationManagerBuilder,正如您在上面的代码中看到的那样 【参考方案1】:

我不知道 Keycloak Spring 适配器,但您可以使用 Spring Security OAuth2 的 Spring Boot 模块来做到这一点。有一个good tutorial given at one of the Spring I/O 2019 labs 显示 1)如何根据 Spring Security DSL 中的一些 JWT 声明(或从 UserInfo 端点检索到的声明)进行授权; 2) 如何提取属性以在 Web 控制器、网页等中使用它们。请参阅那里的“实现客户端”部分。

基本上你需要在你的项目中添加这个依赖(Gradle语法,请适配Maven):

implementation('org.springframework.boot:spring-boot-starter-oauth2-client')

然后:

基于 OIDC 属性/声明的 Spring Security DSL (HTTP Security) 中的授权

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter 

  @Override
  protected void configure(HttpSecurity http) throws Exception 
    http.authorizeRequests()
        .anyRequest()
        .fullyAuthenticated()
        .and()
        .oauth2Client()
        .and()
        .oauth2Login()
        .userInfoEndpoint()
        .userAuthoritiesMapper(userAuthoritiesMapper());
  

  private GrantedAuthoritiesMapper userAuthoritiesMapper() 
    return (authorities) -> 
      Set<GrantedAuthority> mappedAuthorities = new HashSet<>();

      authorities.forEach(
          authority -> 
            if (authority instanceof OidcUserAuthority) 
              OidcUserAuthority oidcUserAuthority = (OidcUserAuthority) authority;

              OidcIdToken idToken = oidcUserAuthority.getIdToken();
              OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();

              List<SimpleGrantedAuthority> groupAuthorities =
                  userInfo.getClaimAsStringList("groups").stream()
                      .map(g -> new SimpleGrantedAuthority("ROLE_" + g.toUpperCase()))
                      .collect(Collectors.toList());
              mappedAuthorities.addAll(groupAuthorities);
            
          );

      return mappedAuthorities;
    ;
  

在网络控制器中使用 OIDC 声明/属性

@GetMapping("/")
  Mono<String> index(@AuthenticationPrincipal OAuth2User oauth2User, Model model) 

    model.addAttribute("fullname", oauth2User.getName());
    model.addAttribute(
        "isCurator",
        ((JSONArray) oauth2User.getAttributes().get("groups")).get(0).equals("library_curator"));
    ...    

来源:https://github.com/andifalk/oidc-workshop-spring-io-2019/tree/master/lab2#implement-the-client

【讨论】:

以上是关于在 Spring Boot 中从 jwt 获取附加属性的主要内容,如果未能解决你的问题,请参考以下文章

如何将一些附加字段添加到此 Spring Boot 服务生成的 JWT 令牌中?

Spring/Boot - JWT 未在 GET 请求中获取

如何在 Spring Boot 中从 Azure SAML 2.0 应用程序获取角色或组

如何使用 JWT 在 Spring Boot 中获取 Refresh Token

如何在 Spring Boot 中从泛型参数(与任何类无关)中获取值

尝试在 Java Spring Boot 中从 H2 数据库中获取相关实体