简介,要求:
现在我正在使用AngularJS编写单页应用程序,该应用程序与Spring REST API进行对话。出于安全考虑,我想设置一个带zuul的反向代理,它代理API的每个请求并验证用户是否经过身份验证。此外,如果用户未经过身份验证,则应将其重定向到OpenAM实例(用作OAuth 2授权服务器)。如果用户已通过身份验证,则应使用Header中的Json Web Token(JWT)将请求转发到API,该JSON Web Token至少包含User的LDAP组。
简而言之,我想拥有类似于本教程中的解决方案的API网关:https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v
现状
我使用以下配置设置Spring Cloud Security和Zuul:
1 > 2 -> false
1 >= 1.0 -> true
TRUE = FALSE -> false
FALSE = FALSE -> true
A OR B -> true
B -> false
A = B -> false
c = C -> true
E > D -> true
B OR (c = B OR (A = A AND c = C AND E > D)) -> true
(A = a OR B = b OR C = c AND ((D = d AND E = e) OR (F = f AND G = g))) -> true
Application类如下所示:
server:
port: 9000
spring:
oauth2:
sso:
home:
secure: false
path: /,/**/*.html
client:
accessTokenUri: http://openam.example.org:8080/OpenAMTest/oauth2/access_token
userAuthorizationUri: http://openam.example.org:8080/OpenAMTest/oauth2/authorize
clientId: bearer-client
clientSecret: clientsecret
scope: openid profile
resource:
userInfoUri: http://openam.example.org:8080/OpenAMTest/oauth2/userinfo
zuul:
routes:
exampleApp:
path: /example-application/**
url: http://openam.example.org:8081/example-application
现在,当我转到“example-application”时,我会转到OpenAM授权登录屏幕。当我输入凭据时,我可以访问“example-application”。控制台登录网关服务:
@SpringBootApplication
@EnableZuulProxy
@EnableOAuth2Sso
public class TestZuulProxy extends SpringBootServletInitializer {
public static void main(String[] args){
SpringApplication.run(TestZuulProxy.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<TestZuulProxy> applicationClass = TestZuulProxy.class;
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {
@Override
public void match(RequestMatchers matchers) {
matchers.anyRequest();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/index.html", "/home.html", "/")
.permitAll().anyRequest().authenticated().and().csrf()
.csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
public class CsrfHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
}
}
Zuul过滤器读取的Http-Header:
2015-06-22 17:14:10.911 INFO 6964 --- [nio-9000-exec-3] o.s.c.s.o.r.UserInfoTokenServices : Getting user info from: http://openam.example.org:8080/OpenAMTest/oauth2/userinfo
2015-06-22 17:14:10.953 INFO 6964 --- [nio-9000-exec-3] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Mon Jun 22 17:14:10 CEST 2015, principal=Aaccf Amar, type=AUTHENTICATION_SUCCESS, data={details=remoteAddress=0:0:0:0:0:0:0:1, sessionId=<SESSION>, tokenType=BearertokenValue=<TOKEN>}]
所以有些事情有效!我有一个访问令牌,可以转发到REST-API。
问题
1)此解决方案并不真正符合我的要求,因为我不希望REST API调用OpenAM的令牌端点。我想要一个带有nessessary声明的JWT传递给Header中的API。我应该手动在网关中创建JWT(例如Zuul过滤器)还是有其他解决方案?
2)在上面的解决方案中,当访问令牌到期时,Zuul会一直转发我到API。为什么是这样? Spring Oauth2不会检查访问令牌是否过期?我该如何实现呢?
3)我还尝试在application.yml中配置tokenInfoUri,但后来我得到了“405 Method Not Allowed”异常,因为我认为OpenAM需要在tokeninfo-Endpoint上发出GET请求。我能以某种方式自定义吗?我需要覆盖/自定义哪些类来更改请求。
如果您有建议,想法或可能的解决方案,请告诉我们!
谢谢!
答案 0 :(得分:0)
如果要在应用程序中使用JWT,请将OpenAM配置为OpenID Connect提供程序(OpenAM 12.0或更高版本)。一旦用户进行了身份验证,OpenAM就会向JWT发出一些关于该用户的声明。您的SPA可以将请求传递到您的服务层。
如果您希望网关在用户会话上强制执行AuthN / AuthZ,您可以使用ForgeRock的OpenIG。这可以作为策略执行点,并且能够内省JWT令牌。