我当前的 Web 应用程序架构有一个网关服务器,可以协调一堆微服务,如果给定原则通过身份验证,授权就会在网关发生,他们可以与一些下游服务对话。
下游服务获取所需的数据以识别给定的经过身份验证的客户端。然而, Spring 证券违约行为开始出现并引发预期:
org.springframework.security.access.AccessDeniedException: Access is denied
鉴于我可以在任何给定的微服务中使用 session ID 和 + XSRF token 来验证用户是否已通过身份验证并知道哪个用户已登录(我目前正在使用 Http Basic)。
我的问题 是否有一种更简单/声明性的方法可以用来代替必须向每个微服务添加过滤器来覆盖 spring securities 默认行为? (参见我的示例伪代码)
资源服务器的 Spring Web 安全配置:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public SessionRepository<ExpiringSession> sessionRepository() {
return new MapSessionRepository();
}
@Bean
HeaderHttpSessionStrategy sessionStrategy() {
return new HeaderHttpSessionStrategy();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().authorizeRequests().anyRequest().authenticated();
final SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter = new SessionRepositoryFilter<ExpiringSession>(
sessionRepository());
sessionRepositoryFilter
.setHttpSessionStrategy(new HeaderHttpSessionStrategy());
http.addFilterBefore(sessionRepositoryFilter,
ChannelProcessingFilter.class).csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
}
public SessionRepository<ExpiringSession> getSessionRepository(){
return sessionRepository();
}
}
资源微服务的 header 值:
KEY: cookie VALUE: XSRF-TOKEN=[token_value]; SESSION=[session_value]
KEY: x-requested-with VALUE: XMLHttpRequest
KEY: x-auth-token VALUE: a32302fd-589b-42e1-8b9d-1991a080e904
...
计划的方法(伪代码)将一个新过滤器附加到 spring securities 过滤器链,如果给定的标志为真,则允许访问安全端点。
**
* A custom filter that can grant access to the current resource
* if there is a valid XSRF-TOKEN and SESSION present in the shared
* session cache.
*/
public class CustomAuthenticationFilter extends AnAppropriateFilterChainFilter {
@Autowired
SessionRepository sessionRepository;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
boolean csrfTokenExists = sessionRepository.findByCsrfTokenId(request);
boolean sessionExists = sessionRepository.findBySessionId(request);
if (csrfTokenExists && sessionExists) {
// everything is okay
} else {
// invalidate the request as being authenticated
throw new InsufficientAuthenticationException("Invalid csrf + session pair");
}
}
}
最佳答案
将我的 spring boot parent 更新到 2.0.1 Release
并将我的 spring cloud 版本更改为 Finchley
后,spring boot 解决了这个问题。
注意 session repository
和 HttpSessionStrategy
不是必需的,
HttpSessionStrategy
自 spring session 成为 spring session core 以来现在已贬值。
使用 redis
和 spring boot
的外部化配置,所有依赖系统都会自动使用该缓存来验证有效 session ,前提是您在类路径上具有 spring 安全性。
请注意,如果您正在使用网关模式和 Zuul Proxy
,请确保您的代理路由在您的应用 YML/properties 中包含 sensitive-headers:
属性,请参阅以下示例:
示例 auth + 网关使用共享 session 缓存的 Springboot 配置。
Auth Gateway
spring:
profiles: dev
redis:
host: localhost
port: 6379
session:
store-type: redis
server:
port: 8080
zuul:
routes:
# local routes
api:
url: forward:/api
path: /api/**
sensitive-headers:
# cloud-resource
resource:
url: http://localhost:9002
path: /resource/**
strip-prefix: false
sensitive-headers:
proxy:
auth:
routes:
resource: passthru
ui: none
api: passthru
security:
sessions: ALWAYS
Some Secured Resource Server
spring:
profiles: dev
redis:
host: localhost
port: 6379
session:
store-type: redis
security:
enabled: false
server:
port: 9002
security:
# Never create a session, but if one exists use it
sessions: NEVER
# don't display the auth box
basic:
enabled: false
management:
security:
enabled: false
关于java - session 验证 - Spring Security with Microservices,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49619327/