/* * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the dreamlu.net developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * Author: Chill 庄骞 (smallchill@163.com) */ package com.vci.ubcs.gateway.filter; import com.alibaba.nacos.common.utils.StringUtils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.vci.ubcs.gateway.provider.AuthProvider; import com.vci.ubcs.gateway.provider.RequestProvider; import com.vci.ubcs.gateway.provider.ResponseProvider; import io.jsonwebtoken.Claims; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springblade.core.jwt.JwtUtil; import org.springblade.core.jwt.props.JwtProperties; import org.springblade.core.launch.constant.TokenConstant; import com.vci.ubcs.gateway.props.AuthProperties; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; /** * 鉴权认证 * * @author Chill */ @Slf4j @Component @AllArgsConstructor public class AuthFilter implements GlobalFilter, Ordered { private final AuthProperties authProperties; private final ObjectMapper objectMapper; private final JwtProperties jwtProperties; private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { //校验 Token 放行 String originalRequestUrl = RequestProvider.getOriginalRequestUrl(exchange); String path = exchange.getRequest().getURI().getPath(); if (isSkip(path) || isSkip(originalRequestUrl)) { return chain.filter(exchange); } //校验 Token 合法性 ServerHttpResponse resp = exchange.getResponse(); String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_KEY); String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_KEY); if (StringUtils.isBlank(headerToken) && StringUtils.isBlank(paramToken)) { return unAuth(resp, "缺失令牌,鉴权失败"); } String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken; String token = JwtUtil.getToken(auth); Claims claims = JwtUtil.parseJWT(token); if (token == null || claims == null) { return unAuth(resp, "请求未授权"); } //判断 Token 状态 if (jwtProperties.getState()) { String tenantId = String.valueOf(claims.get(TokenConstant.TENANT_ID)); String userId = String.valueOf(claims.get(TokenConstant.USER_ID)); String accessToken = JwtUtil.getAccessToken(tenantId, userId, token); if (!token.equalsIgnoreCase(accessToken)) { return unAuth(resp, "令牌已失效"); } } return chain.filter(exchange); } private boolean isSkip(String path) { return AuthProvider.getDefaultSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path)) || authProperties.getSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path)) || authProperties.getAuth().stream().anyMatch(auth -> antPathMatcher.match(auth.getPattern(), path)) || authProperties.getBasic().stream().anyMatch(basic -> antPathMatcher.match(basic.getPattern(), path)) || authProperties.getSign().stream().anyMatch(sign -> antPathMatcher.match(sign.getPattern(), path)); } private Mono unAuth(ServerHttpResponse resp, String msg) { resp.setStatusCode(HttpStatus.UNAUTHORIZED); resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); String result = ""; try { result = objectMapper.writeValueAsString(ResponseProvider.unAuth(msg)); } catch (JsonProcessingException e) { log.error(e.getMessage(), e); } DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8)); return resp.writeWith(Flux.just(buffer)); } @Override public int getOrder() { return -100; } }