当前位置: 首页 > 知识库问答 >
问题:

使用Spring Security在OAuth2 web客户端上存储JWT令牌

仰成天
2023-03-14

我正在使用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;
    }
}
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的成功身份验证流结束时,框架正在通过提供的InMemoryOuth2AuthorizedClientService在内存中存储OAuth2AuthorizedClient模型下获得的访问和刷新JWT令牌。

我正在尝试找出如何覆盖此行为,以便令牌在服务器重新启动后仍然可用。并保持用户在此基础上登录。

我应该只提供一个自定义的OAuth2AuthorizedClientService实现吗?如何配置Spring Security来使用它?该自定义实现是否应该将令牌存储在cookie中?

共有1个答案

艾骏
2023-03-14

我应该只提供一个自定义的OAuth2AuthorizedClientService实现吗?

我想是的,用于解决您的用例

如何配置Spring Security来使用它?

@EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Client()
                .authorizationCodeGrant()
                    .authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
                    ...
    }

    private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
        return new HttpCookieOAuth2AuthorizationRequestRepository();
    }
}
 类似资料:
  • 我是JWT新手,我只是将其作为JSON中的java对象返回,并制作了一些过滤器,以便它可以像Spring Security中的session_id一样工作。 但是我不明白JWT是如何存储在客户端的,在服务器响应之后它会去哪里?它是否由coockies中的所有浏览器自动存储?所有浏览器都支持JWT吗? 我很感激你的回答。

  • 客户端存储

  • 我使用节点js来验证用户并发回JWT令牌。我是使用角6.0前端。我的问题是在客户端将这个令牌存储在哪里?如果在客户端使用localstorage,如何保护此令牌?

  • 我看过的大多数博客文章都建议使用httpOnly cookies,以便在客户端(javascript应用程序)上安全地存储jwt令牌。我对此有几个问题(我在那些博客文章中找不到)。 < li >如果jwt令牌存储在httpOnly cookie中,javascript应用程序将无法访问令牌,也无法知道当前用户的身份验证状态。我们该如何处理? < li >“使用httpOnly cookie”在AP

  • 我的SPA应用程序使用以下体系结构(来源): 这假设我的客户端应用程序知道刷新令牌,因为如果没有用户凭据(例如电子邮件/密码),我需要它来请求新的访问令牌。 我的问题:在客户端应用程序中,刷新令牌存储在哪里?关于这个话题有很多问题/答案,但是关于刷新标记,答案并不清楚。 访问令牌和刷新令牌不应存储在本地/会话存储器中,因为它们不是存放任何敏感数据的地方。因此,我会将访问令牌存储在一个cookie中

  • 我正在实现一个需要身份验证的REST服务。我正在使用JWT。 现在,Android应用程序在登录时发送一个请求,获得一个令牌,并且必须在每个后续请求的头中发送令牌。 我的问题是,如何存储令牌,或者我应该将其存储在哪里? 共享偏好 SQLite数据库 归档 最好的做法是什么?还是我完全错了?