需求背景
在微服务的场景下,采用了Spring Cloud Oauth2进行token的管理,实现认证和受权,在这下背景下,有两种解决方案:html
网关统一鉴权
此模式适用于网关下的全部模式都是经过一种模式进行鉴权操做,能够统一管理java
微服务模块各自鉴权
此模式适用于网关下的各个模块有不一样的鉴权模式,针对不一样的业务场景须要知足不一样的实现,如采用oauth二、shiro、签名等方式。react
下文就网关统一鉴权的实现方式提供解决方案,以供参考git
实现方案
经过过滤器的方式实现统一拦截,下面以核心代码的方式展现,具体全部代码能够参考Matecloud项目。web
过滤器代码
package vip.mate.gateway.filter; import io.jsonwebtoken.Claims; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import vip.mate.core.cloud.props.MateUaaProperties; import vip.mate.core.common.constant.MateConstant; import vip.mate.core.common.constant.Oauth2Constant; import vip.mate.core.common.util.ResponseUtil; import vip.mate.core.common.util.SecurityUtil; /** * 网关统一的token验证 * * @author pangu */ @Slf4j @Component @AllArgsConstructor public class UaaFilter implements GlobalFilter, Ordered { private final MateUaaProperties mateUaaProperties; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 若是未启用网关验证,则跳过 if (!mateUaaProperties.getEnable()) { return chain.filter(exchange); } log.error("getIgnoreUrl:{}", mateUaaProperties.getIgnoreUrl()); // 若是在忽略的url里,则跳过 String path = replacePrefix(exchange.getRequest().getURI().getPath()); String requestUrl = exchange.getRequest().getURI().getRawPath(); if (ignore(path) || ignore(requestUrl)) { return chain.filter(exchange); } // 验证token是否有效 ServerHttpResponse resp = exchange.getResponse(); String headerToken = exchange.getRequest().getHeaders().getFirst(Oauth2Constant.HEADER_TOKEN); if (headerToken == null) { return unauthorized(resp, "没有携带Token信息!"); } Claims claims = SecurityUtil.getClaims(headerToken.replace("bearer ","")); if (claims == null) { return unauthorized(resp, "token已过时或验证不正确!"); } return chain.filter(exchange); } /** * 检查是否忽略url * @param path 路径 * @return boolean */ private boolean ignore(String path) { return mateUaaProperties.getIgnoreUrl().stream() .map(url -> url.replace("/**", "")) .anyMatch(path::startsWith); } /** * 移除模块前缀 * @param path 路径 * @return String */ private String replacePrefix(String path) { if (path.startsWith("/mate")) { return path.substring(path.indexOf("/",1)); } return path; } private Mono<Void> unauthorized(ServerHttpResponse resp, String msg) { return ResponseUtil.webFluxResponseWriter(resp, "application/json;charset=UTF-8", HttpStatus.UNAUTHORIZED, msg); } @Override public int getOrder() { return MateConstant.MATE_UAA_FILTER_ORDER; } public static void main(String[] args) { } }
方法上面也有注解,先经过注解的方式熟悉一下实现流程。spring
配置类
package vip.mate.core.cloud.props; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 验证权限配置 * * @author pangu * @date 2020-10-28 */ @Setter @RefreshScope @ConfigurationProperties(prefix = "mate.uaa") public class MateUaaProperties { /** * 忽略URL,List列表形式 */ private List<String> ignoreUrl = new ArrayList<>(); /** * 是否启用网关鉴权模式 */ private Boolean enable = false; /** * 监控中心和swagger须要访问的url */ private static final String[] ENDPOINTS = { "/oauth/**", "/actuator/**", "/v2/api-docs/**", "/v2/api-docs-ext/**", "/swagger/api-docs", "/swagger-ui.html", "/doc.html", "/swagger-resources/**", "/webjars/**", "/druid/**", "/error/**", "/assets/**", "/auth/logout", "/auth/code" }; /** * 自定义getter方法,并将ENDPOINTS加入至忽略URL列表 * @return List */ public List<String> getIgnoreUrl() { if (!ignoreUrl.contains("/doc.html")) { Collections.addAll(ignoreUrl, ENDPOINTS); } return ignoreUrl; } public Boolean getEnable() { return enable; } }
此配置类,主要配置忽略鉴权的URL和是否启用网关鉴权的开关。 其中须要在Nacos里增长以下配置,ignore-url配置的是忽略的url地址,在这里能够动态配置,并实时刷新。json
mate: uaa: enable: false ignore-url: - /auth/login/** - /auth/callback/** - /auth/sms-code
至此,配置完成。api
代码案例
MateCloud微服务:https://gitee.com/matevip/matecloudapp