简体   繁体   中英

get additional attributes from jwt in spring boot

I am developing a spring boot service that is protected by keycloak and it accepts jwt bearer token for authentication.

I also configured swagger and registered it as a public client, so when I make a request from swagger-ui a keycloak generates a JWT token which swagger then uses for authentication when making requests to the api.

I also created 2 additional private mappers for user information. Now I'd like to get those 2 attributes inside my spring controller.

Bellow is my example code.
I feel a bit lost in spring security and various ways of doing stuff (spring security / oauth2 / keycloak etc....) so some explanation along the solution would be really appreciated.

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://stackoverflow.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 Security config

@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();
    }



}

example controller

    @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;
    }

I don't know for the Keycloak Spring adapter but you can do this with the Spring Boot module for Spring Security OAuth2. There is a good tutorial given at one of the Spring I/O 2019 labs showing 1) how to authorize based on some JWT claim (or claim retrieved from UserInfo endpoint) in Spring Security DSL; 2) how to extract attributes to use them in a web controller, web page, etc. See section "Implement the client" there.

Basically, you need to add this dependency to your project (Gradle syntax, please adapt for Maven):

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

Then:

Authorization in Spring Security DSL (HTTP Security) based on OIDC attributes/claims

@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;
    };
  }
}

Use OIDC claims/attributes in a web controller

@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"));
    ...    
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM