无法将 JSESSIONID 传递给前端域

问题描述

我有一个应用程序,它使用 Spring Boot 作为后端,使用 ReactJS 作为前端。我在登录时使用了 Linkedin OAuth 来授权用户

当有人登录时,会创建 JSESSIONID cookie 并将其存储在后端域 (http://www.my-backend.com) 中。要在前端使用 API,我需要在前端 (JSESSIONID) 中存储 http://www.my-frontend.com。有人可以帮我解决这个问题吗?

我想要实现的目标:也在前端域中创建 JSESSIONID cookie。

Application.yml

spring:
  thymeleaf:
    cache: false
  security:
    oauth2:
      client:
        registration:
          linkedin:
            client-id: ${CLIENT_ID}
            client-secret: ${CLIENT-SECRET}
            client-authentication-method: post
            authorization-grant-type: authorization_code
            redirect-uri: "http://my-frontend.com"
            scope: r_liteprofile,r_emailaddress
            client-name: Linkedin
        provider:
          linkedin:
            authorization-uri: https://www.linkedin.com/oauth/v2/authorization
            token-uri: https://www.linkedin.com/oauth/v2/accesstoken
            user-info-uri: https://api.linkedin.com/v2/me?projection=(id,localizedFirstName,localizedLastName,profilePicture(displayImage~:playableStreams))
            user-name-attribute: id
            email-address-uri: https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MysqL5InnoDBDialect
    hibernate:
      ddl-auto: update
  datasource:
    url: jdbc:MysqL://${DB_URL}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: ${DB_USER_NAME}
    password: ${DB_USER_PASSWORD}
  jmx:
    unique-names: true

SecurityConfig.java

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf()
      .disable()
      .authorizeRequests()
      .antMatchers("/api/admin/**")
      .hasAnyAuthority("ADMIN")
      .antMatchers("/api/programs")
      .permitAll()
      .antMatchers("/api/**")
      .authenticated()
      .anyRequest()
      .permitAll()
      .and()
      .logout()
      .permitAll()
      .and()
      .exceptionHandling()
      .authenticationEntryPoint(
        new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)
      )
      .and()
      .oauth2Login()
      .failureHandler(new AuthFailureHandler())
      .tokenEndpoint()
      .accesstokenResponseClient(authorizationCodetokenResponseClient());
  }

  private OAuth2AccesstokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodetokenResponseClient() {
    OAuth2AccesstokenResponseHttpMessageConverter converter = new OAuth2AccesstokenResponseHttpMessageConverter();
    converter.setTokenResponseConverter(new AuthAccesstokenResponseConverter());

    RestTemplate restTemplate = new RestTemplate(
      Arrays.asList(new FormHttpMessageConverter(),converter)
    );
    restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());

    DefaultAuthorizationCodetokenResponseClient responseClient = new DefaultAuthorizationCodetokenResponseClient();
    responseClient.setRestOperations(restTemplate);

    return responseClient;
  }

  private static class AuthFailureHandler
    implements AuthenticationFailureHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void onAuthenticationFailure(
      HttpServletRequest request,HttpServletResponse response,AuthenticationException exception
    )
      throws IOException,servletexception {
      Map<String,Object> data = new HashMap<>();
      response.setContentType("application/json");
      response.setStatus(HttpStatus.UNAUTHORIZED.value());
      data.put("exception",exception.getMessage());
      response.getoutputStream().println(objectMapper.writeValueAsstring(data));
    }
  }
}

AuthAccesstokenResponseConverter.java

public class AuthAccesstokenResponseConverter
        implements Converter<Map<String,String>,OAuth2AccesstokenResponse> {
    private static final Set<String> TOKEN_RESPONSE_ParaMETER_NAMES
            = Stream.of(OAuth2ParameterNames.ACCESS_TOKEN,OAuth2ParameterNames.TOKEN_TYPE,OAuth2ParameterNames.EXPIRES_IN,OAuth2ParameterNames.REFRESH_TOKEN,OAuth2ParameterNames.ScopE)
            .collect(Collectors.toSet());
    private OAuth2Accesstoken.TokenType defaultAccesstokenType = OAuth2Accesstoken.TokenType.BEARER;

    @Override
    public OAuth2AccesstokenResponse convert(Map<String,String> tokenResponseParameters) {
        String accesstoken = tokenResponseParameters.get(OAuth2ParameterNames.ACCESS_TOKEN);

        OAuth2Accesstoken.TokenType accesstokenType = defaultAccesstokenType;
        if (OAuth2Accesstoken.TokenType.BEARER
                .getValue().equalsIgnoreCase(tokenResponseParameters
                        .get(OAuth2ParameterNames.TOKEN_TYPE))) {
            accesstokenType = OAuth2Accesstoken.TokenType.BEARER;
        }

        long expiresIn = 0;
        if (tokenResponseParameters.containsKey(OAuth2ParameterNames.EXPIRES_IN)) {
            expiresIn = Long.parseLong(tokenResponseParameters
                    .get(OAuth2ParameterNames.EXPIRES_IN));
        }

        Set<String> scopes = Collections.emptySet();
        if (tokenResponseParameters.containsKey(OAuth2ParameterNames.ScopE)) {
            String scope = tokenResponseParameters.get(OAuth2ParameterNames.ScopE);
            scopes = Arrays.stream(StringUtils.delimitedListToStringArray(scope," "))
                    .collect(Collectors.toSet());
        }

        Map<String,Object> additionalParameters = new LinkedHashMap<>();
        tokenResponseParameters.entrySet().stream()
                .filter(e -> !TOKEN_RESPONSE_ParaMETER_NAMES.contains(e.getKey()))
                .forEach(e -> additionalParameters.put(e.getKey(),e.getValue()));

        return OAuth2AccesstokenResponse.withToken(accesstoken)
                .tokenType(accesstokenType)
                .expiresIn(expiresIn)
                .scopes(scopes)
                .additionalParameters(additionalParameters)
                .build();
    }

    public final void setDefaultAccesstokenType(OAuth2Accesstoken.TokenType
                                                        defaultAccesstokenType) {
        Assert.notNull(defaultAccesstokenType,"defaultAccesstokenType cannot be null");
        this.defaultAccesstokenType = defaultAccesstokenType;
    }
}

WebClientConfig.java

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(ClientRegistrationRepository clientRegistrationRepository,OAuth2AuthorizedClientRepository authorizedClientRepository) {
        ServletoAuth2AuthorizedClientExchangeFilterFunction oauth2 =
                new ServletoAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository,authorizedClientRepository);
        return WebClient.builder()
                .apply(oauth2.oauth2Configuration())
                .build();
    }
}

完整代码在这里https://github.com/piumal1999/scholarx

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)