简体   繁体   English

Spring 启动 oauth2:无 userInfo 端点 - 如何直接在客户端从 JWT 访问令牌加载身份验证(主体)

[英]Spring boot oauth2: No userInfo endpoint - How to load the authentication (Principal) from the JWT access token directly in the client

I am setting up an oauth 2.0 client application which will redirect the users to an external IDP (Authorization Server) to sign in. My app will undergo the regular oauth 2 Authorization code grant flow - 1)Redirect the users to sign in. 2)Obtain the access code first 3) Use the access code to obtain the token.我正在设置一个 oauth 2.0 客户端应用程序,它将用户重定向到外部 IDP(授权服务器)以登录。我的应用程序将经历常规 oauth 2 授权代码授予流程 - 1)重定向用户登录。2)先获取访问码 3) 使用访问码获取令牌。 Since the external IDP is using oauth 2 just for authentication, they are not going to provide a user-info endpoint url (required by an OIDC provider) to get the user details.由于外部 IDP 使用 oauth 2 仅用于身份验证,因此他们不会提供用户信息端点 url(由 OIDC 提供商要求)来获取用户详细信息。 Instead they want us to get the claims from the JWT token directly and make any authorizations in our app.相反,他们希望我们直接从 JWT 令牌中获取声明,并在我们的应用程序中进行任何授权。 I am unable to find the right code/configuration which will not expect a user-info endpoint and instead decode the jwt directly for loading the authentication.我无法找到不期望用户信息端点的正确代码/配置,而是直接解码 jwt 以加载身份验证。 In the below demo code, if I were to decode the user details from the JWT token issued by OKTA without calling its userInfo endpoint, how do I do that?在下面的演示代码中,如果我要从 OKTA 发出的 JWT 令牌中解码用户详细信息而不调用其 userInfo 端点,我该怎么做?

I am using spring boot 2.x release using the standard oauth client configuration provided in the spring reference sample social oauth2 projects.我正在使用 spring 启动 2.x 版本,使用 spring 参考示例社交 oauth2 项目中提供的标准 oauth 客户端配置。

I would really appreciate if someone could guide me in the right path.如果有人能引导我走上正确的道路,我将不胜感激。 Thank you!谢谢!

gradle configuration gradle配置

buildscript {
ext {
    springBootVersion = '2.2.0.RELEASE'
}
repositories {
    mavenLocal()
    mavenCentral()
}
dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
configurations {
compile.exclude module: 'spring-boot-starter-logging'
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-log4j2:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}")
compile("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:${springBootVersion}")
compile("org.webjars:jquery:2.1.1")
compile("org.webjars:bootstrap:3.2.0")
compile("org.webjars:webjars-locator-core:0.42")
}

application.yml应用程序.yml

github:
  client:
     clientId: <clientId>
     clientSecret: <clientSecret>
     accessTokenUri: https://github.com/login/oauth/access_token
     userAuthorizationUri: https://github.com/login/oauth/authorize
     tokenName: oauth_token
     authenticationScheme: query
     clientAuthenticationScheme: form
  resource:
     userInfoUri: https://api.github.com/user

okta:
  client:
   clientId: <clientId>
   clientSecret: <clientSecret>
   accessTokenUri: https://<okta-sub-domain>/oauth2/default/v1/token
   userAuthorizationUri: https://<okta-sub-domain>/oauth2/default/v1/authorize
   scope: openid profile email
 resource:
  userInfoUri: https://<okta-sub-domain>/oauth2/default/v1/userinfo

OAuth2Config.java OAuth2Config.java

@Configuration
@EnableOAuth2Client
public class Oauth2Config extends WebSecurityConfigurerAdapter {

@Autowired
OAuth2ClientContext oauth2ClientContext;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/**").authorizeRequests()
    .antMatchers("/", "/login**", "/webjars/**", "/error**")
    .permitAll()
  .anyRequest()
    .authenticated()
            .and().logout().logoutSuccessUrl("/").permitAll()
            .and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);;
    http.csrf().disable();
}

private Filter ssoFilter() {
    CompositeFilter filter = new CompositeFilter();
    List<Filter> filters = new ArrayList<>();

    OAuth2ClientAuthenticationProcessingFilter githubFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/github");
    OAuth2RestTemplate githubTemplate = new OAuth2RestTemplate(github(), oauth2ClientContext);
    githubFilter.setRestTemplate(githubTemplate);
    UserInfoTokenServices tokenServices = new UserInfoTokenServices(githubResource().getUserInfoUri(), github().getClientId());
    tokenServices.setRestTemplate(githubTemplate);
    githubFilter.setTokenServices(tokenServices);
    filters.add(githubFilter);

    OAuth2ClientAuthenticationProcessingFilter oktaFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/okta");
    OAuth2RestTemplate oktaTemplate = new OAuth2RestTemplate(okta(), oauth2ClientContext);
    oktaFilter.setRestTemplate(oktaTemplate);
    tokenServices = new UserInfoTokenServices(oktaResource().getUserInfoUri(), okta().getClientId());        
    tokenServices.setRestTemplate(oktaTemplate);
    oktaFilter.setTokenServices(tokenServices);
    filters.add(oktaFilter);

    filter.setFilters(filters);
    return filter;
}

//Client registration
@Bean
@ConfigurationProperties("github.client")
public AuthorizationCodeResourceDetails github() {
    return new AuthorizationCodeResourceDetails();
}

//user info endpoints
@Bean
@ConfigurationProperties("github.resource")
public ResourceServerProperties githubResource() {
    return new ResourceServerProperties();
}

@Bean
@ConfigurationProperties("okta.client")
public AuthorizationCodeResourceDetails okta() {
    return new AuthorizationCodeResourceDetails();
}

@Bean
@ConfigurationProperties("okta.resource")
public ResourceServerProperties oktaResource() {
    return new ResourceServerProperties();
}

//For Handling Redirects
@Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
    FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<>();
    registration.setFilter(filter);
    registration.setOrder(-100);
    return registration;
}

} }

A simple controller with an endpoint used by html page一个简单的 controller 与 html 页面使用的端点

@RestController
public class UserController {

@GetMapping("/user")
public Principal user(Principal principal) {        
    return principal;
}

} }

@SpringBootApplication
public class Oauth2Application {

public static void main(String[] args) {
    SpringApplication.run(Oauth2Application.class, args);
}

} }

DefaultReactiveOAuth2UserService looks up the userInfo. DefaultReactiveOAuth2UserService查找用户信息。 We can simply introduce a new ReactiveOAuth2UserService implementation to take values from the token, eg:我们可以简单地引入一个新的ReactiveOAuth2UserService实现来从令牌中获取值,例如:

@Service
public class GttOAuth2UserService implements ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User>  {

    @Override
    public Mono<OAuth2User> loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {
        final List<GrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("authority"));
        final Map<String, Object> attributes = oAuth2UserRequest.getAdditionalParameters();
        final OAuth2User user = new DefaultOAuth2User(authorities, attributes, "email");
        return Mono.just(user);
    }
}

(in your case it may be the non-reactive equivalents) (在您的情况下,它可能是非反应性等价物)

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

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