需求背景
在微服務的場景下,採用了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