![](/img/trans.png)
[英]How to attach UserDetails to Principal received from JWT token using Spring Oauth2
[英]Spring boot oauth2: No userInfo endpoint - How to load the authentication (Principal) from the JWT access token directly in the client
我正在設置一個 oauth 2.0 客戶端應用程序,它將用戶重定向到外部 IDP(授權服務器)以登錄。我的應用程序將經歷常規 oauth 2 授權代碼授予流程 - 1)重定向用戶登錄。2)先獲取訪問碼 3) 使用訪問碼獲取令牌。 由於外部 IDP 使用 oauth 2 僅用於身份驗證,因此他們不會提供用戶信息端點 url(由 OIDC 提供商要求)來獲取用戶詳細信息。 相反,他們希望我們直接從 JWT 令牌中獲取聲明,並在我們的應用程序中進行任何授權。 我無法找到不期望用戶信息端點的正確代碼/配置,而是直接解碼 jwt 以加載身份驗證。 在下面的演示代碼中,如果我要從 OKTA 發出的 JWT 令牌中解碼用戶詳細信息而不調用其 userInfo 端點,我該怎么做?
我正在使用 spring 啟動 2.x 版本,使用 spring 參考示例社交 oauth2 項目中提供的標准 oauth 客戶端配置。
如果有人能引導我走上正確的道路,我將不勝感激。 謝謝!
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")
}
應用程序.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
@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;
}
}
一個簡單的 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
查找用戶信息。 我們可以簡單地引入一個新的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);
}
}
(在您的情況下,它可能是非反應性等價物)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.