基于SpringCloudGateway实现接口鉴权

一、在pom.xml中导入SpringCloudGateway jar包

XML 复制代码
dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

二、在application.yaml中配置接口路径

java 复制代码
url-auth:
  whitelist:
    - /demo/login
    - /demo/captcha

三、属性配置类

java 复制代码
@Data
@Configuration
@ConfigurationProperties(prefix = "url-auth")
public class UrlAuthProperties {
    /***白名单,不做鉴权处理,只做简单的业务处理*/
    private List<String> whitelist=new ArrayList<>();
    /**
     * 黑名单
     */
    private List<String> blacklist  = new ArrayList<>();
    /**
     * 忽略名单,不做任何处理
     */
    private List<String> ignoreList = new ArrayList<>();
}

四、封装基础拦截器

java 复制代码
/**
 * 基础拦截器
 *
 */
@Slf4j
public abstract class BaseFilter implements GlobalFilter, Ordered {
    @Autowired
    private UrlAuthProperties urlAuthProperties;
    /**
     * 白名单校验
     */
    public boolean isWhitelist(ServerHttpRequest request) {
        boolean result = false;
        String path = request.getPath().toString();
        HttpMethod httpMethod = request.getMethod();
        if (httpMethod != null && httpMethod.name().equals(HttpMethod.OPTIONS.name())) {
        	result = true;
        } else if (StringUtils.isNotBlank(path)) {
            List<String> urls = urlAuthProperties.getWhitelist();
            result = matchUrl(urls,path);
        }
        if(result == true) {
        	log.info("path:{}, whitelist:{}", path, result);
        }
        return result;
    }
    
    /**
     * antPathMatcher.match("/user/*", "/user/a"); 
     * antPathMatcher.match("/user/**", "/user/a/b"); 
     * antPathMatcher.match("/user/name", "/user/a");
     * antPathMatcher.isPattern("user/{id}");
     * @param urls
     * @param path
     * @return
     */
    private Boolean matchUrl(List<String> urls,String path) {
    	AntPathMatcher antPathMatcher = new AntPathMatcher(); 
    	for (Iterator<String> iterator = urls.iterator(); iterator.hasNext();) {
			String string = (String) iterator.next();
			if(string.equals(path) || antPathMatcher.match(string, path)) {
				return true;
			}
		}
		return false;
    }

    /**
     * 忽略列表处理
     */
    public boolean isIgnoreList(ServerHttpRequest request) {
        boolean result = false;
        String path = request.getPath().toString();
        HttpMethod httpMethod = request.getMethod();
        if (httpMethod != null && httpMethod.name().equals(HttpMethod.OPTIONS.name())) {
            result = true;
        } else if (StringUtils.isNotBlank(path)) {
            List<String> urls = urlAuthProperties.getIgnoreList();
            return urls.contains(path);
        }
        log.debug("path:{}, IgnoreList:{}", path, result);
        return result;
    }

    /**
     * 黑名单校验
     * 在黑名单中的请求链接将返回true
     */
    public boolean isBlacklist(ServerHttpRequest request) {
        boolean result = false;
        String path = request.getPath().toString();
        HttpMethod httpMethod = request.getMethod();
        if (httpMethod != null && httpMethod.name().equals(HttpMethod.OPTIONS.name())) {
            result = true;
        } else if (StringUtils.isNotBlank(path)) {
            List<String> urls = urlAuthProperties.getBlacklist();
            return urls.contains(path);
        }
        log.debug("path:{},blacklist:{}", path, result);
        return result;
    }

    /***从当前请求(请求头/cookie)获取授权参数*/
    public String getFromHeaderAndCookie(ServerHttpRequest request, String key) {
        HttpHeaders headers = request.getHeaders();
        // 1.从请求头中获取
        String paramValue = headers.getFirst(key);
        if (StrUtil.isBlank(paramValue)) {
            // 2.从cookie中获取
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            HttpCookie cookie = cookies.getFirst(key);
            paramValue = Optional.ofNullable(cookie).map(HttpCookie::getValue).orElse(null);
        }
        return paramValue;
    }
}

五、实际接口拦截入口

java 复制代码
@Slf4j
@Component
public class SecurityFilter extends BaseFilter {
    private static final String AUTHORIZATION = "Authorization";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        // 白名单直接放行不做token校验
        if (isWhitelist(request)) {
            return chain.filter(exchange);
        }
        String authorization = getFromHeaderAndCookie(request, AUTHORIZATION);
        if (StringUtils.isBlank(authorization) || JwtUtils.isExpire(authorization)) {
            throw new BusinessException(CommonErrorEnum.UNAUTHORIZED);
        }

        LoginContext loginContext = JwtUtils.getCurrentUser(authorization);
        loginContext.setClientType(ClientType.ADMIN);
        LoginContextHolder.set(loginContext);

        String text = JSON.toJSONString(loginContext);
        log.info("LoginContext:{}", text);
        String unicode = UnicodeUtil.toUnicode(text, true);
        String[] headerValues = new String[]{unicode};

        ServerHttpRequest newRequest = exchange.getRequest().mutate()
                .header(LoginContextConst.LOGIN_USER, headerValues)
                .header(LoginContextConst.TOKEN, authorization).build();
        //构建新的ServerWebExchange实例
        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

        return chain.filter(newExchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
相关推荐
周某某~2 分钟前
四.抽象工厂模式
java·设计模式·抽象工厂模式
异常君29 分钟前
高并发数据写入场景下 MySQL 的性能瓶颈与替代方案
java·mysql·性能优化
烙印60133 分钟前
MyBatis原理剖析(二)
java·数据库·mybatis
你是狒狒吗36 分钟前
TM中,return new TransactionManagerImpl(raf, fc);为什么返回是new了一个新的实例
java·开发语言·数据库
鳄鱼杆41 分钟前
服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?
服务器·spring boot·centos
勤奋的知更鸟1 小时前
Java编程之组合模式
java·开发语言·设计模式·组合模式
千|寻1 小时前
【画江湖】langchain4j - Java1.8下spring boot集成ollama调用本地大模型之问道系列(第一问)
java·spring boot·后端·langchain
爱编程的喵1 小时前
深入理解JavaScript原型机制:从Java到JS的面向对象编程之路
java·前端·javascript
on the way 1231 小时前
行为型设计模式之Mediator(中介者)
java·设计模式·中介者模式
保持学习ing1 小时前
Spring注解开发
java·深度学习·spring·框架