实现代码如下:
@Component @Slf4j public class TokenFilter implements GlobalFilter, Ordered { private static final String BEAR_HEADER = "Bearer "; /** * 该值要和auth-server中配置的签名相同 * * com.kdyzm.spring.security.auth.center.config.TokenConfig#SIGNING_KEY */ private static final String SIGNING_KEY = "auth123"; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION); //如果没有token,则直接返回401 if(StringUtils.isEmpty(token)){ return unAuthorized(exchange); } //验签并获取PayLoad String payLoad; try { Jwt jwt = JwtHelper.decodeAndVerify(token.replace(BEAR_HEADER,""), new MacSigner(SIGNING_KEY)); payLoad = jwt.getClaims(); } catch (Exception e) { log.error("验签失败",e); return unAuthorized(exchange); } //将PayLoad数据放到header ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); builder.header("token-info", payLoad).build(); //继续执行 return chain.filter(exchange.mutate().request(builder.build()).build()); } private Mono<Void> unAuthorized(ServerWebExchange exchange){ exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } /** * 将该过滤器的优先级设置为最高,因为只要认证不通过,就不能做任何事情 * * @return */ @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } } 三、资源服务修改原来资源服务已经集成了OAuth2.0、Spring Security、JWT等组件,根据现在的设计方案,需要删除OAuth2.0和JWT组件,只留下Spring Security组件。
1.移除OAuth2.0、JWT组件这里要删除maven依赖,同时将相关配置删除
第一步,删除maven依赖,直接将以下两个依赖移除就好
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency>第二步,删除相关配置
将ResouceServerConfig、TokenConfig两个类直接删除 即可。
2.添加过滤器这里需要使用过滤器做,首先写一个过滤器,实现OncePerRequestFilter接口,该过滤器的作用就是获取网关传过来的token-info明文数据,封装成JwtTokenInfo对象,并将该相关信息添加到SpringSecurity上下文以备之后的鉴权使用。
代码实现如下:
@Component @Slf4j public class AuthFilterCustom extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ObjectMapper objectMapper = new ObjectMapper(); String tokenInfo=request.getHeader("token-info"); if(StringUtils.isEmpty(tokenInfo)){ log.info("未找到token信息"); filterChain.doFilter(request,response); return; } JwtTokenInfo jwtTokenInfo = objectMapper.readValue(tokenInfo, JwtTokenInfo.class); log.info("tokenInfo={}",objectMapper.writeValueAsString(jwtTokenInfo)); List<String> authorities1 = jwtTokenInfo.getAuthorities(); String[] authorities=new String[authorities1.size()]; authorities1.toArray(authorities); //将用户信息和权限填充 到用户身份token对象中 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(jwtTokenInfo.getUser_name(),null, AuthorityUtils.createAuthorityList(authorities)); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); //将authenticationToken填充到安全上下文 SecurityContextHolder.getContext().setAuthentication(authenticationToken); filterChain.doFilter(request,response); } } 3.将过滤器注册到过滤器链修改WebSecurityConfig类,使用如下方法注册过滤器:
.addFilterAfter(authFilterCustom, BasicAuthenticationFilter.class)//添加过滤器同时,一定要关闭session功能,否则会出现上下文缓存问题
.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS);//禁用session