Spring Cloud Gateway實現網關統一鑑權,網關統一Token認證

需求背景

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

相關文章
相關標籤/搜索