我当前的Web应用程序架构有一个网关服务器,它协调一堆微服务,如果给定的原则经过身份验证,它们可以在网关上进行授权,它们可以与某些下游服务进行通信。
下游服务获取所需数据以识别给定的经过身份验证的客户端。然而,春季证券违约行为开始并抛出预期:
org.springframework.security.access.AccessDeniedException: Access is denied
鉴于我可以在任何给定的微服务中使用会话ID和+ XSRF令牌来验证用户是否已经过身份验证并知道哪个用户已登录(我目前正在使用Http Basic)。
我的问题是否有一种更简单/声明的方法可用于代替必须为每个微服务添加过滤器以覆盖弹簧证券的默认行为? (参见我的示例伪代码)
资源服务器的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();
}
}
资源微服务中的标头值:
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证券过滤器链,如果给定标志为真,则允许访问受保护的端点。
**
* 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");
}
}
}
答案 0 :(得分:0)
将我的spring boot parent更新为2.0.1 Release
并将spring spring版本更改为Finchley
后,问题已通过spring boot解决。
注意session repository
和HttpSessionStrategy
不是必需的,
HttpSessionStrategy
现已折旧,因为春季会议成为春季会议的核心。
使用redis
和spring boot
的externalised配置,所有从属系统都会自动使用该缓存来验证有效会话,前提是您的类路径具有弹簧安全性。
注意,如果您使用的是网关模式,Zuul Proxy
确保您的代理路由在您的应用YML /属性中包含sensitive-headers:
属性,请参阅以下示例:
使用Springboot配置共享会话缓存的示例auth +网关。
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
某些安全资源服务器
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