在过去的几天里,我一直在到处寻找如何做到这一点,最终决定承认失败并寻求帮助,请!!!
我遵循了Dave Syer博士关于Angular和Spring Security性的教程,特别是将Zuul代理用作api网关,并使用Redis的Spring会话(https://github.com/spring-guides/tut-spring-security-and-angular-js/tree/master/double#_sso_with_oauth2_angular_js_and_spring_security_part_v)
我遇到的问题是,我正在通过网关从具有以下标头的外部应用程序调用资源rest服务:
String plainCreds = "user:password";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.getEncoder().encode(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
通过zuul进行身份验证,然后路由资源,以便通过redis访问经过身份验证的会话。
问题是会话似乎只在请求响应后才提交网关中的redis。所以发生的是,当我用头调用资源服务时,我可以看到成功的身份验证发生在网关和正在创建的会话中,但是我在资源中得到一个403,因为会话在它被创建后不在redis中通过zuul路由。
但是,如果出现错误,请抓取会话id并将其添加到标头中,然后重试,因为现在我的已验证会话在路由后可用于资源项目。
请有人告诉我如何通过网关获取我的电话,以便在同一请求中进行身份验证和路由,好吗?
谢谢你,贾斯汀
我的APIGateway(Zuul)由Apache Httpd代理,由Mellon模块(SAML 2.0)保护。在身份提供者上成功进行身份验证后,mellon模块正确地将读取的一些标头注入到SAML响应中,但是第一个请求以403状态代码失败。
我也在使用SpringSecurity,为了解决这个问题,我在安全过滤链上添加了一个简单的过滤器,以确保正确创建SecurityContext:
@Component
public class MellonFilter extends OncePerRequestFilter {
private final Logger log = LoggerFactory.getLogger(MellonFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String mellonId=req.getHeader("mellon-nameid");
if(mellonId==null||mellonId.isEmpty())
;//do filterchain
else {
UserWithRoles userWithRoles = new UserWithRoles();
userWithRoles.setUsername(mellonId);
SilUserDetails details = new SilUserDetails(userWithRoles);
SilAuthenticationPrincipal silPrincipal = null;
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("Some roles");
silPrincipal = new SilAuthenticationPrincipal(details, true, authorities);
SecurityContextHolder.clearContext();
SecurityContextHolder.getContext().setAuthentication(silPrincipal);
}
filterChain.doFilter(req,httpServletResponse);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
if(SecurityContextHolder.getContext().getAuthentication()!=null&&SecurityContextHolder.getContext().getAuthentication() instanceof SilAuthenticationPrincipal)
return true;
return false;
}
}
然后,我需要一个ZumFilter来保存会话(在Redis上)并传播实际会话id:
public class ZuulSessionCookieFilter extends ZuulFilter {
private final Logger log = LoggerFactory.getLogger(ZuulSessionCookieFilter.class);
@Autowired
private SessionRepository repository;
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpSession httpSession = context.getRequest().getSession();
httpSession.setAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
SecurityContextHolder.getContext()
);
Session session = repository.findById(httpSession.getId());
context.addZuulRequestHeader("cookie", "SESSION=" + base64Encode(httpSession.getId()));
log.debug("ZuulPreFilter session proxy: {} and {}", session.getId(),httpSession.getId());
return null;
}
private static String base64Encode(String value) {
byte[] encodedCookieBytes = Base64.getEncoder().encode(value.getBytes());
return new String(encodedCookieBytes);
}
}
希望这个解决方案对大家有帮助。
我对这里的延迟回复感到非常抱歉,南非最伟大的事情之一是我们伟大的电信业。呵呵,我已经有一段时间没有在家上网了,我的源代码在我的家用电脑上。
是的,史蒂夫在正确的轨道上。这里有两个问题需要解决:
>
Spring会话仅在响应初始传入请求时将经过身份验证的会话提交给redis。因此,第一步是遵循steve提供的链接,以确保每当会话更改时,Spring会话都会提交到redis。
Zuul不会在初始路由上传播这个新认证的会话。因此,您需要做的是使用zuul预过滤器(周围有很多例子),它获取经过身份验证的会话标识,然后将其添加到网关后面的资源的zuul请求中。您将在zuul请求上看到一个setter方法来设置会话id。
如果您不这样做,您将需要执行两个调用,一个用于验证并从spring会话获取redis中的有效会话id,然后使用经过验证的会话id执行后续调用。
我确实和它斗争了一段时间,但当我让它工作的时候,它是当场的。我扩展了这个解决方案,不仅适用于http basic,还添加了jwt令牌实现。
希望这有帮助,只要我在家里连接好,我就可以发布源代码。
祝你好运!贾斯汀
我关注了贾斯汀·泰勒在不同页面上的帖子,所以这是他的解决方案。它使我有意义的解决方案与源代码在这里:
@EnableRedisHttpSession(redisFlushMode=redisFlushMode.IMMEDIATE)
,可将会话数据立即保存到Redis中。这里有文档
@Component
public class SessionSavingZuulPreFilter extends ZuulFilter {
@Autowired
private SessionRepository repository;
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpSession httpSession = context.getRequest().getSession();
Session session = repository.getSession(httpSession.getId());
context.addZuulRequestHeader("Cookie", "SESSION=" + httpSession.getId());
log.info("ZuulPreFilter session proxy: {}", session.getId());
return null;
}
}
再一次-这不是我的解决方案-证书交给贾斯汀·泰勒。
我试图通过编写一个简单的REST应用程序来学习Spring Boot,该应用程序将登录用户()并显示当前用户的信息()。我正在使用Redis进行会话。 按预期工作:它返回主体并在浏览器和Redis中设置会话cookie。 然而,随后的请求返回。我错过了什么? : : < code > index controller . Java : :
在身份验证等情况下,与会话相比,使用JWTs有什么优势? 它是作为独立方法使用还是在会话中使用?
我不熟悉spring微服务世界。由于我处于学习阶段,我尝试并实施了以下内容。 > 路由(能够使用Spring云网关进行路由) 负载平衡(Netflix Eureka) 限速和断路器 我只需要一些澄清和建议,说明在这些情况下该怎么做: 因为我已经创建了身份验证/授权作为一个单独的微服务集中。现在我如何实现这样的每个请求必须包含jwt令牌和通过API网关调用其他微服务也应该检查哪个用户有权限访问其他微
我正在使用Vert。后端为x,前端为AngularJS。 Vert. x服务器使用POST和GET方法接收HTTP操作。不知何故,我为每个请求获取不同的会话ID。 以下是来自我的LoginFormHandler类句柄例程的代码片段。 我正在将用户对象放入当前会话中。然后我移动到新页面并向Vert. x服务器发送POST请求。在那个POST处理程序中,我正在尝试获取会话对象: 我没有得到用户。此外,
我一直在搜索net,试图找到任何定义如何在流星和响应路由器4中处理身份验证的地方。 基本上,我希望某些路由只对经过身份验证的用户可用。有相关文件吗? 阿西尔
我想通过Spring Cloud介绍Zuul作为一个API网关在少数服务前面。 我关心的问题: > 网关将位于许多服务的前面 某些服务可能公开不需要身份验证的endpoint null