You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Security OAuth2配置:从HttpOnly Cookie获取Access Token

Alright, let's get your Spring Boot resource server pulling JWT tokens from an HttpOnly Cookie instead of the Authorization header. I'll walk you through the key configurations using spring-security-oauth2 and spring-security-jwt, including custom token extraction, resource server setup, and a bonus on setting the cookie from your authorization server.

First, you need a custom TokenExtractor to pull the JWT from the request's cookies instead of the header. This component tells Spring Security where to look for the token.

import org.springframework.security.oauth2.provider.token.TokenExtractor;
import org.springframework.stereotype.Component;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

@Component
public class CookieTokenExtractor implements TokenExtractor {

    // Name of your HttpOnly cookie holding the JWT
    private static final String ACCESS_TOKEN_COOKIE = "ACCESS_TOKEN";
    private static final String BEARER_PREFIX = "Bearer ";

    @Override
    public String extract(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (ACCESS_TOKEN_COOKIE.equals(cookie.getName())) {
                    String token = cookie.getValue();
                    // Add Bearer prefix if your decoder expects it (most do)
                    if (!token.startsWith(BEARER_PREFIX)) {
                        token = BEARER_PREFIX + token;
                    }
                    return token;
                }
            }
        }
        // Optional: Fall back to Authorization header if cookie isn't present
        return request.getHeader("Authorization");
    }
}
2. Configure the Resource Server

Next, update your resource server configuration to use the custom token extractor. This tells Spring Security to use your cookie-based logic instead of the default header extraction.

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenExtractor;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private final TokenExtractor cookieTokenExtractor;

    // Inject the custom token extractor via constructor
    public ResourceServerConfig(TokenExtractor cookieTokenExtractor) {
        this.cookieTokenExtractor = cookieTokenExtractor;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        // Set the custom token extractor
        resources.tokenExtractor(cookieTokenExtractor);
        // Add your resource ID (if your authorization server uses them)
        resources.resourceId("your-resource-identifier");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                // Configure CSRF protection: adjust based on your app's needs
                // If you're using a SPA with cross-domain requests, you may need to tweak this
                .csrf().ignoringAntMatchers("/api/**");
    }
}
3. Ensure JWT Decoder is Properly Configured

Make sure your JWT decoder is set up to validate the tokens from the cookie. This depends on whether you're using symmetric or asymmetric signing.

Example with JWKS (Asymmetric Signing):

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;

@Configuration
public class JwtConfig {

    @Bean
    public JwtDecoder jwtDecoder() {
        // Replace with your authorization server's JWKS endpoint
        return NimbusJwtDecoder.withJwkSetUri("https://your-auth-server/.well-known/jwks.json").build();
    }
}

Example with Symmetric Key:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

@Configuration
public class JwtConfig {

    @Bean
    public JwtDecoder jwtDecoder() {
        String secretKey = "your-strong-symmetric-secret-key";
        SecretKey key = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        return NimbusJwtDecoder.withSecretKey(key).build();
    }
}

If you control the authorization server, here's how to set the JWT as an HttpOnly cookie when issuing tokens. This uses Spring Security's OAuth2 Authorization Server features.

import org.springframework.http.ResponseCookie;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;

@Component
public class CookieTokenCustomizer implements OAuth2TokenCustomizer<OAuth2TokenContext> {

    @Override
    public void customize(OAuth2TokenContext context) {
        if (OAuth2AccessToken.TOKEN_TYPE_VALUE.equals(context.getTokenType().getValue())) {
            OAuth2AccessToken accessToken = context.getToken();
            HttpServletResponse response = context.get(HttpServletResponse.class);

            ResponseCookie accessTokenCookie = ResponseCookie.from("ACCESS_TOKEN", accessToken.getTokenValue())
                    .httpOnly(true) // Critical: Prevents XSS attacks by blocking JS access
                    .secure(true) // Enable in production: Only send cookie over HTTPS
                    .sameSite("Strict") // Mitigates CSRF; use "Lax" if needed for cross-site flows
                    .path("/") // Adjust to your app's base path
                    .maxAge(accessToken.getExpiresAt().getEpochSecond() - System.currentTimeMillis() / 1000)
                    .build();

            response.addHeader("Set-Cookie", accessTokenCookie.toString());
        }
    }
}
Key Notes to Remember
  • CSRF Protection: When using HttpOnly cookies, ensure your CSRF configuration aligns with your app's architecture. For SPAs, you may need to expose the CSRF token to the frontend and include it in requests.
  • CORS Configuration: If your frontend is on a different domain, enable credential support in CORS to allow cookies to be sent cross-domain:
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import java.util.List;
    
    @Configuration
    public class CorsConfig {
    
        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedOrigins(List.of("https://your-frontend-domain.com"));
            config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
            config.setAllowedHeaders(List.of("*"));
            config.setAllowCredentials(true); // Required for cookie-based auth
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", config);
            return source;
        }
    }
    
  • Secure Cookie: Always set secure(true) in production to ensure cookies are only transmitted over HTTPS.

内容的提问来源于stack exchange,提问作者ionutt93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:15:01