Commit a3a53293 by 刘鑫

CI: 添加外部接口AK校验, 并且不在校验白名单内的接口不再放行

1 parent 7c3debd7
package com.dituhui.pea.gateway.config;
import java.util.Set;
import com.alibaba.fastjson.JSON;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.constants.Globals;
import com.dituhui.pea.enums.RedisKeyGroup;
import com.dituhui.pea.gateway.commom.RedisService;
import com.dituhui.pea.pojo.UserLoginDTO;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import com.dituhui.pea.constants.Globals;
import com.dituhui.pea.enums.RedisKeyGroup;
import com.dituhui.pea.gateway.commom.RedisService;
import com.dituhui.pea.pojo.UserLoginDTO;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {
/**
* 白名单
*/
private static final Set<String> authWhiteList = Sets.newHashSet("/pea-user/login", "/pea-user/login/",
"/pea-user/refreshAppkey", "/pea-user/refreshAppkey/");
private static final Gson gson = new Gson();
@Autowired
RedisService redisService;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String url = exchange.getRequest().getPath().toString();
// 判断是否属于白名单中
if (authWhiteList.contains(url)) {
log.info("whiteList:{} ip:{}", url, getRemoteIP(exchange));
return chain.filter(exchange);
}
// 下面的代码从Http Header的Authorization中获取token,也可以从其他header,cookie等中获取,看客户端怎么传递token
HttpHeaders headers = exchange.getRequest().getHeaders();
String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
// W3C的HTTP1.0规范: Authorization : <type> <authorization-parameters>
// Basic用于http-basic 认证;
// Bearer 常见于OAuth和JWT授权;
// AwS4-HMAC - SHA256 AwS授权
String authToken = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
authToken = authHeader.substring(7);
}
if (StringUtils.isEmpty(authToken)) {
authToken = exchange.getRequest().getQueryParams().getFirst("token");
}
UserLoginDTO userDTO = null;
if (StringUtils.isNotEmpty(authToken)) {
if (log.isTraceEnabled()) {
log.trace("token is {}", authToken);
}
// 查询token对应的用户
String value = redisService.get(RedisKeyGroup.authToken + ":" + authToken);
if (null != value) {
userDTO = gson.fromJson(value, UserLoginDTO.class);
}
}
// ak登录处理
if (StringUtils.isEmpty(authToken)) {
String ak = exchange.getRequest().getQueryParams().getFirst("ak");
if (log.isTraceEnabled()) {
log.trace("ak is {}", ak);
}
if (StringUtils.isNotEmpty(ak)) {
// 验证ak,设置userDTO
String value = redisService.get(RedisKeyGroup.appKey + ":" + ak);
if (StringUtils.isNotEmpty(value)) {
// 验证成功,设置为管理员
// AppDTO appDTO = gson.fromJson(value, AppDTO.class);
// String secret = appDTO.getSecret();
userDTO = new UserLoginDTO();
userDTO.setId(Globals.SUPER_ADMIN_ID);
}
}
}
if (userDTO == null) {
log.info("未授权访问{} ip:{}", url, getRemoteIP(exchange));
} else {
log.info("用户:{} id:{} 访问{}", userDTO.getAccount(), userDTO.getId(), url);
// 获取当前的请求对象信息
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
// 向header中设置新的key,存储解析好的token对应基本信息
builder.header("userId", userDTO.getId());
// 向下游传递
// Authentication authentication = new UsernamePasswordAuthenticationToken(userDTO.getAccount(), null, null);
// SecurityContextHolder.getContext().setAuthentication(authentication);
return chain.filter(exchange.mutate().request(builder.build()).build());
}
return chain.filter(exchange);
}
/**
* 客户端ip
*
* @param exchange
* @return
*/
private String getRemoteIP(ServerWebExchange exchange) {
String clientIp = "";
if (StringUtils.isNotEmpty(exchange.getRequest().getHeaders().getFirst("x-forwarded-for"))) {
clientIp = exchange.getRequest().getHeaders().getFirst("x-forwarded-for");
} else if (StringUtils.isNotEmpty(exchange.getRequest().getHeaders().getFirst("X-Forwarded-For"))) {
clientIp = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
} else if (StringUtils.isNotEmpty(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress())) {
clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
}
if ("0:0:0:0:0:0:0:1".equals(clientIp)) {
clientIp = "127.0.0.1";
}
return clientIp;
}
@Override
public int getOrder() {
return -1;
}
/**
* 白名单
*/
private static final Set<String> authWhiteList = Sets.newHashSet("/pea-user/login", "/pea-user/login/",
"/pea-user/refreshAppkey", "/pea-user/refreshAppkey/");
private static final Gson gson = new Gson();
@Autowired
RedisService redisService;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String url = exchange.getRequest().getPath().toString();
// 判断是否属于白名单中
if (authWhiteList.contains(url)) {
log.info("whiteList:{} ip:{}", url, getRemoteIP(exchange));
return chain.filter(exchange);
}
// 下面的代码从Http Header的Authorization中获取token,也可以从其他header,cookie等中获取,看客户端怎么传递token
HttpHeaders headers = exchange.getRequest().getHeaders();
String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
// W3C的HTTP1.0规范: Authorization : <type> <authorization-parameters>
// Basic用于http-basic 认证;
// Bearer 常见于OAuth和JWT授权;
// AwS4-HMAC - SHA256 AwS授权
String authToken = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
authToken = authHeader.substring(7);
}
if (StringUtils.isEmpty(authToken)) {
authToken = exchange.getRequest().getQueryParams().getFirst("token");
}
UserLoginDTO userDTO = null;
if (StringUtils.isNotEmpty(authToken)) {
if (log.isTraceEnabled()) {
log.trace("token is {}", authToken);
}
// 查询token对应的用户
String value = redisService.get(RedisKeyGroup.authToken + ":" + authToken);
if (null != value) {
userDTO = gson.fromJson(value, UserLoginDTO.class);
}
}
// ak登录处理
if (StringUtils.isEmpty(authToken)) {
final String ak = getParams(exchange, "ak", headers);
if (log.isTraceEnabled()) {
log.trace("ak is {}", ak);
}
if (StringUtils.isNotEmpty(ak)) {
// 验证ak,设置userDTO
String value = redisService.get(RedisKeyGroup.appKey + ":" + ak);
if (StringUtils.isNotEmpty(value)) {
// 验证成功,设置为管理员
// AppDTO appDTO = gson.fromJson(value, AppDTO.class);
// String secret = appDTO.getSecret();
//TODO 参数签名校验
final String sign = getParams(exchange, "sign", headers);
//计算签名
userDTO = new UserLoginDTO();
userDTO.setId(Globals.SUPER_ADMIN_ID);
}
}
}
if (userDTO == null) {
log.info("未授权访问{} ip:{}", url, getRemoteIP(exchange));
return noPower(exchange);
} else {
log.info("用户:{} id:{} 访问{}", userDTO.getAccount(), userDTO.getId(), url);
// 获取当前的请求对象信息
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
// 向header中设置新的key,存储解析好的token对应基本信息
builder.header("userId", userDTO.getId());
// 向下游传递
// Authentication authentication = new UsernamePasswordAuthenticationToken(userDTO.getAccount(), null, null);
// SecurityContextHolder.getContext().setAuthentication(authentication);
return chain.filter(exchange.mutate().request(builder.build()).build());
}
}
/**
* 解析所有参数
*
*/
private Map<String, String> parseGetParams(ServerWebExchange exchange) {
// params
Map<String, String> params = Maps.newHashMap();
//请求路劲参数
Map<String, String> urlRequestParams = exchange.getRequest().getQueryParams().toSingleValueMap();
return params;
}
private String getParams(ServerWebExchange exchange, String paramKey, HttpHeaders headers) {
String param = exchange.getRequest().getQueryParams().getFirst(paramKey);
if (StringUtils.isBlank(param)) {
param = headers.getFirst(paramKey);
}
return param;
}
/**
* 网关拒绝,返回Result
*/
private Mono<Void> noPower(ServerWebExchange serverWebExchange) {
// 权限不够拦截
serverWebExchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
Result<?> data = Result.failed();
DataBuffer buffer = serverWebExchange.getResponse().bufferFactory().wrap(JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8));
ServerHttpResponse response = serverWebExchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
/**
* 客户端ip
*
* @param exchange
* @return
*/
private String getRemoteIP(ServerWebExchange exchange) {
String clientIp = "";
if (StringUtils.isNotEmpty(exchange.getRequest().getHeaders().getFirst("x-forwarded-for"))) {
clientIp = exchange.getRequest().getHeaders().getFirst("x-forwarded-for");
} else if (StringUtils.isNotEmpty(exchange.getRequest().getHeaders().getFirst("X-Forwarded-For"))) {
clientIp = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
} else if (StringUtils.isNotEmpty(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress())) {
clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
}
if ("0:0:0:0:0:0:0:1".equals(clientIp)) {
clientIp = "127.0.0.1";
}
return clientIp;
}
@Override
public int getOrder() {
return -1;
}
}
/*
* Begin license text.
* Copyright (c) 2020 — 2021 Liu Xin && Zhang Lei lsy_xin@163.com
* All rights reserved
* End license text.
*/
package com.dituhui.pea.gateway.utils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
/**
* @author zl
*/
public class SignUtil {
/**
* 对输入参数签名
*
* @param params 参数
* @param secret 密钥
* @return
* @throws IOException
*/
public static String signRequest(Map<String, String> params, String secret) {
try {
// 第一步:参数排序
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
// 第二步:把所有参数名和参数值串在一起
StringBuilder query = new StringBuilder();
for (String key : keys) {
String value = params.get(key);
if (StringUtils.isNotEmpty(key) && !StringUtils.equalsIgnoreCase(key, "sign")
&& StringUtils.isNotEmpty(value)) {
query.append(key).append(value);
}
}
// 第三步:使用MD5/HMAC加密
return DigestUtils.md5Hex(query.toString() + secret);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!