【发布时间】:2019-10-02 00:37:03
【问题描述】:
我正在使用 Spring Boot 2.1.3 和 Spring Security 5.1.3 实现 OAuth2 Web 应用程序客户端,该客户端通过授权代码授予类型从授权服务器获取 JWT 令牌并调用受保护的资源服务器。
这是目前的实现方式:
安全配置和一个用于调用受保护资源的restTemplate bean:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.and()
.oauth2Client()
.and().logout().logoutSuccessUrl("/");
}
@Bean
public RestTemplate restTemplate(OAuth2AuthorizedClientService clientService) {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new AuthorizationHeaderInterceptor(clientService));
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
在 restTemplate 中添加授权标头(来自框架的 InMemoryOAuth2AuthorizedClientService)的拦截器:
public class AuthorizationHeaderInterceptor implements ClientHttpRequestInterceptor {
private OAuth2AuthorizedClientService clientService;
public AuthorizationHeaderInterceptor(OAuth2AuthorizedClientService clientService) {
this.clientService = clientService;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String accessToken = null;
if (authentication != null && authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) {
OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) authentication;
String clientRegistrationId = auth.getAuthorizedClientRegistrationId();
OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(clientRegistrationId, auth.getName());
accessToken = client.getAccessToken().getTokenValue();
request.getHeaders().add("Authorization", "Bearer " + accessToken);
}
return execution.execute(request, bytes);
}
}
以及调用受保护资源服务器的控制器:
@Controller
@RequestMapping("/profile")
public class ProfileController {
@Autowired
private RestTemplate restTemplate;
@Value("${oauth.resourceServerBase}")
private String resourceServerBase;
@GetMapping
public String getProfile(Model model) {
Profile profile = restTemplate.getForEntity(resourceServerBase + "/api/profile/", Profile.class).getBody();
model.addAttribute("profile", profile);
return "profile";
}
}
OAuth2客户端配置直接在application.yml中:
spring:
security:
oauth2:
client:
registration:
auth-server:
client-id: webClient
client-secret: clientSecret
scope: read,write
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8081/client/login/oauth2/code/auth-server
provider:
auth-server:
authorization-uri: http://localhost:8080/auth-server/oauth/authorize
token-uri: http://localhost:8080/auth-server/oauth/token
user-info-uri: http://localhost:8082/resource-server/users/info
user-name-attribute: user_name
在进行一些调试后,我观察到,在通过 OAuth2LoginAuthtenticationFilter 的成功身份验证流程结束时,框架正在通过提供的 InMemoryOAuth2AuthorizedClientService 将获得的访问权限和刷新 JWT 令牌存储在内存中的 OAuth2AuthorizedClient 模型下。
我正在尝试找出如何覆盖此行为,以便令牌在服务器重新启动后仍然可用。并基于此保持用户登录。
我应该只提供一个自定义的 OAuth2AuthorizedClientService 实现吗?我如何配置 Spring Security 来使用它?这个自定义实现是否应该将令牌存储在 cookie 中?
【问题讨论】:
标签: spring spring-boot spring-security oauth-2.0 spring-security-oauth2