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

相关文章
相关标签/搜索