我正在尝试为我的数据服务实现网关。我所有的数据服务都受到JWT身份验证的保护(即每个请求都必须具有“ Authorization”标头,否则数据服务将以“ Unauthorized”响应)。我希望我的网关也验证所有对授权标头的请求。我该如何实现?由于Spring Cloud Gateway基于反应模型,因此我无法使用相同的配置。以下是其他数据服务的配置:
application.properties
security.jwt.signing-key=secret-key
security.resource.id=abc.dataService.com
securityConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* Defines beans that protect resources using OAuth2 and JWT tokens
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AllClaimsMappingAccessTokenConverter customAccessTokenConverter;
@Value("${security.jwt.signing-key}")
private String signingKey;
@Value("${security.cors.allowedOrigins}")
private String allowedOrigins;
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
converter.setAccessTokenConverter(customAccessTokenConverter);
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(allowedOrigins.split(",")));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE", "PUT", "PATCH"));
configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization", "X-Auth-Token"));
configuration.setMaxAge(TimeUnit.DAYS.toSeconds(2));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
resourceServerConfig.java
import java.io.IOException;
import java.time.Instant;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.AuthenticationException;
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.ResourceServerTokenServices;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceServerConfig.class);
@Value("${security.resource.id}")
private String resourceId;
@Autowired
private ResourceServerTokenServices tokenServices;
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.resourceId(resourceId).tokenServices(tokenServices);
resources.authenticationEntryPoint(restAuthenticationEntryPoint);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.requestMatchers()
.and()
.authorizeRequests()
.antMatchers("/**").authenticated();
}
@Component("restAuthenticationEntryPoint")
public static class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final String ERROR_JSON_TEMPLATE = "{ \"errors\": [ { \"id\": %d, \"status\": 401, \"title\": \"Not Authorized\", \"detail\": \"%s\" } ], \"meta\": {} }";
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex)
throws IOException, ServletException {
long instant = Instant.now().toEpochMilli();
LOGGER.error("Auth exception at {}", instant, ex);
response.getWriter()
.println(String.format(ERROR_JSON_TEMPLATE, instant, ex.getMessage()));
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.flushBuffer();
}
}
}
TokenConverter
import java.util.Map;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.stereotype.Component;
@Component
public class AllClaimsMappingAccessTokenConverter extends DefaultAccessTokenConverter {
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
OAuth2Authentication authentication = super.extractAuthentication(claims);
authentication.setDetails(claims);
return authentication;
}
}