如何在 Rest 模板中重用来自用户 (authorization_code) 的 oauth2 令牌
How to reuse oauth2 token from user (authorization_code) in a Rest Template
我有 3 个申请
- 前端应用程序
- OAuth2 认证服务器
- REST api (RepositoryRestResources)
我的用户必须先登录才能使用前端应用程序。这是通过 SSO 发生的。他们收到一个令牌,该令牌在被允许进入之前由客户端验证。
我想重复使用此令牌来发出 api 请求。我的 REST api 应用程序使用相同的 SSO 登录(它是前端客户端的资源)进行保护,但我不知道如何 "add the authorization header" 在我用于 [=32= 的 RestTemplate 中使用] 请求。
我这样创建我的 restTemplate:
public static RestTemplate build()
{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(new Jackson2HalModule());
mapper.registerModule(new JavaTimeModule());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
converter.setObjectMapper(mapper);
return new RestTemplate(Arrays.asList(converter));
}
我的资源服务器配置:
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{
@Value("${resource.id}")
private String resourceId;
@Override
public void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
{
resources.resourceId(resourceId);
}
@Bean
public static TokenEnhancer tokenEnhancer()
{
return new JwtTokenEnhancer();
}
@Bean
public static JwtAccessTokenConverter accessTokenConverter()
{
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "somesecret".toCharArray());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("pair"));
return converter;
}
@Bean
public static TokenStore tokenStore()
{
return new JwtTokenStore(accessTokenConverter());
}
}
您可以在您的方法顶部使用 @PreAuthorize(ROLE)
,因此当调用此方法时,他将检查 Token 是否具有使用该方法所需的 ROLE。
当然,您需要配置 API 以连接到您的 OAuth 数据库。
示例:
@PreAuthorize("ROLE_ADMIN")
public void deleteAll(){
...
}
我使用拦截器修复了它并从安全上下文中手动添加令牌。
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new OAuthInterceptor());
其中拦截器定义为:
public class OAuthInterceptor implements ClientHttpRequestInterceptor
{
@Autowired
private AuthenticationHolder holder;
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
{
if (holder.getToken() == null)
{
//throw new IOException("Token not set");
System.out.println("##################### Token not set! ###################");
}
else
{
System.out.println("##################### Token found: " + holder.getToken());
HttpHeaders headers = request.getHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + holder.getToken());
}
return execution.execute(request, body);
}
}
我使用我在客户端应用程序中实现的接口:
public interface AuthenticationHolder
{
String getToken();
}
@Bean
public AuthenticationHolder getAuthenticationHolder()
{
return () ->
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails)
{
return ((OAuth2AuthenticationDetails) authentication.getDetails()).getTokenValue();
}
return null;
};
}
我有 3 个申请
- 前端应用程序
- OAuth2 认证服务器
- REST api (RepositoryRestResources)
我的用户必须先登录才能使用前端应用程序。这是通过 SSO 发生的。他们收到一个令牌,该令牌在被允许进入之前由客户端验证。
我想重复使用此令牌来发出 api 请求。我的 REST api 应用程序使用相同的 SSO 登录(它是前端客户端的资源)进行保护,但我不知道如何 "add the authorization header" 在我用于 [=32= 的 RestTemplate 中使用] 请求。
我这样创建我的 restTemplate:
public static RestTemplate build()
{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(new Jackson2HalModule());
mapper.registerModule(new JavaTimeModule());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
converter.setObjectMapper(mapper);
return new RestTemplate(Arrays.asList(converter));
}
我的资源服务器配置:
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{
@Value("${resource.id}")
private String resourceId;
@Override
public void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
{
resources.resourceId(resourceId);
}
@Bean
public static TokenEnhancer tokenEnhancer()
{
return new JwtTokenEnhancer();
}
@Bean
public static JwtAccessTokenConverter accessTokenConverter()
{
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "somesecret".toCharArray());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("pair"));
return converter;
}
@Bean
public static TokenStore tokenStore()
{
return new JwtTokenStore(accessTokenConverter());
}
}
您可以在您的方法顶部使用 @PreAuthorize(ROLE)
,因此当调用此方法时,他将检查 Token 是否具有使用该方法所需的 ROLE。
当然,您需要配置 API 以连接到您的 OAuth 数据库。
示例:
@PreAuthorize("ROLE_ADMIN")
public void deleteAll(){
...
}
我使用拦截器修复了它并从安全上下文中手动添加令牌。
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new OAuthInterceptor());
其中拦截器定义为:
public class OAuthInterceptor implements ClientHttpRequestInterceptor
{
@Autowired
private AuthenticationHolder holder;
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
{
if (holder.getToken() == null)
{
//throw new IOException("Token not set");
System.out.println("##################### Token not set! ###################");
}
else
{
System.out.println("##################### Token found: " + holder.getToken());
HttpHeaders headers = request.getHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + holder.getToken());
}
return execution.execute(request, body);
}
}
我使用我在客户端应用程序中实现的接口:
public interface AuthenticationHolder
{
String getToken();
}
@Bean
public AuthenticationHolder getAuthenticationHolder()
{
return () ->
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails)
{
return ((OAuth2AuthenticationDetails) authentication.getDetails()).getTokenValue();
}
return null;
};
}