基于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;
    }
}
相关推荐
mldong5 小时前
引擎从不发一条消息:jeeflow 的两类扩展点与消息模块的分工
java·架构
君顾15 小时前
智慧零售实战指南:从技术架构到落地方案全解析
java·开发语言·零售
zhanghe6876 小时前
es的密码带有特殊字符,导出
java
pnoker6 小时前
IoT DC3 概念解读:把设备抽象成一套语义模板——位号、指令、事件与面向智能体的设备建模
java·人工智能·物联网·iot·dc3
my_realmy6 小时前
Java SE 基础学习笔记(一):面向对象、继承多态、抽象接口与异常(JDK 8)
java·多线程·并发··生产者消费者模式
天远数科7 小时前
风险治理实战:基于天远车信盟出险构建自动化理赔核保流水线
java·网络·人工智能·自动化
步行cgn7 小时前
YAML 的语法规则
spring boot·后端
骇客野人7 小时前
SpringBoot电商系统用户注册、登录、留存及数据埋点设计与落地实施方案
java·spring boot·后端
摇滚侠7 小时前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 数据库初始化机制 阅读笔记 36
数据库·spring boot·笔记
qiuhaipeng17 小时前
Claude code 升级后上下文长度变短问题
java·前端·数据库