在网关收到请求后,可以对请求进行一步步的过滤,这里考虑使用责任链模式。每个处理器通过其next指向下一个处理器。
package processors;
import Util.HttpUtil;
import common.HttpStatueCode;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
public interface Processor {
void process(ChannelHandlerContext ctx, FullHttpRequest request);
void setNext(Processor processor);
//如果某个处理器需要拒绝请求时可以调用该方法拒绝请求
default void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest request, HttpResponseStatus status) {
HttpUtil httpUtil = new HttpUtil();
FullHttpResponse response = httpUtil.createHttpResponse(request, status);
httpUtil.sendResponse(ctx, response);
}
}
HttpUtil 主要用于封装响应数据和发送响应
package Util;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import common.HttpStatueCode;
import common.ResponseMsg;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import java.nio.charset.StandardCharsets;
public class HttpUtil {
public FullHttpResponse createHttpResponse(FullHttpRequest request,HttpResponseStatus status) {
// 创建响应对象
ResponseMsg responseObject = new ResponseMsg(status.reasonPhrase(), status.code());
// 将对象序列化为 JSON 字符串
String responseBody = JSON.toJSONString(responseObject);
FullHttpResponse response = new DefaultFullHttpResponse(
request.protocolVersion(),
HttpResponseStatus.OK,
Unpooled.copiedBuffer(responseBody, StandardCharsets.UTF_8)
);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
return response;
}
public FullHttpResponse createHttpResponse(FullHttpRequest request,String responseBody) {
// 创建响应对象
FullHttpResponse response = new DefaultFullHttpResponse(
request.protocolVersion(),
HttpResponseStatus.OK,
Unpooled.copiedBuffer(responseBody, StandardCharsets.UTF_8)
);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
return response;
}
public void sendResponse(ChannelHandlerContext ctx, FullHttpResponse response) {
ctx.writeAndFlush(response).addListener(future -> {
if (!future.isSuccess()) {
// 处理发送失败
future.cause().printStackTrace();
}
});
}
}
这里的鉴权处理器实现一种方法通过jwt鉴权。
package processors.auth;
import Util.JwtUtil;
import Util.ObjectUtil;
import common.HttpStatueCode;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import processors.Processor;
import server.ConfigReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class JwtAuthProcessor implements Processor {
private Processor nextProcessor;
//密钥map 一个路由前缀对应一个密钥 可以根据配置文件配置 后面会写配置文件的加载
private Map<String, String> secretKeyMap;
public JwtAuthProcessor() {
secretKeyMap = ConfigReader.getSecretMap();
}
@Override
public void process(ChannelHandlerContext ctx, FullHttpRequest request) {
String authorization = request.headers().get("Authorization");
String uri = request.uri();
Set<String> prefixSet = secretKeyMap.keySet();
for (String prefix : prefixSet) {
if (uri.startsWith(prefix)) {
try {
if(ObjectUtil.isEmpty(authorization)|| !JwtUtil.validateToken(secretKeyMap.get(prefix),authorization)){
throw new Exception();
}
}catch (Exception e){
sendHttpResponse(ctx, request, HttpStatueCode.AUTH_ERROR);
return;
}
break;
}
}
/**
* validateToken抛出异常或者验证失败则返回
*/
Optional.ofNullable(nextProcessor).ifPresent(p -> p.process(ctx, request));
}
@Override
public void setNext(Processor processor) {
this.nextProcessor = processor;
}
}
鉴权思路,首先验证请求中是否存在 Authorization请求头,该请求头中封装了token。之后验证该token是否在有效期和是否正确,验证不正确validateToken方法会抛出异常。如果验证通过且下一个处理器存在直接调用下一个处理器。
jwtUtil
package Util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import server.ConfigReader;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
private static final long EXPIRATION_TIME = 86400000; // 24小时
private static final String ALGORITHM = "HmacSHA512"; // 使用的算法
public JwtUtil() {
}
// 生成JWT令牌的方法
public static String generateToken(String secretKet,Map<String, Object> claims) {
Algorithm algorithm = Algorithm.HMAC512(secretKet);
long currentTimeMillis = System.currentTimeMillis();
Date expirationDate = new Date(currentTimeMillis + EXPIRATION_TIME);
// 使用Claims生成JWT
JWTCreator.Builder jwtBuilder = JWT.create()
.withIssuedAt(new Date(currentTimeMillis))
.withExpiresAt(expirationDate);
for (Map.Entry<String, Object> entry : claims.entrySet()) {
if (entry.getValue() instanceof String) {
jwtBuilder.withClaim(entry.getKey(), (String) entry.getValue());
} else if (entry.getValue() instanceof Integer) {
jwtBuilder.withClaim(entry.getKey(), (Integer) entry.getValue());
} else if (entry.getValue() instanceof Boolean) {
jwtBuilder.withClaim(entry.getKey(), (Boolean) entry.getValue());
} else if (entry.getValue() instanceof Long) {
jwtBuilder.withClaim(entry.getKey(), (Long) entry.getValue());
} else if (entry.getValue() instanceof Double) {
jwtBuilder.withClaim(entry.getKey(), (Double) entry.getValue());
} else if (entry.getValue() instanceof Date) {
jwtBuilder.withClaim(entry.getKey(), (Date) entry.getValue());
}
}
return jwtBuilder.sign(algorithm);
}
// 生成简单的JWT令牌示例
public static String createToken(String secretKet,String username) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", username); // 添加自定义信息
return generateToken(secretKet,claims);
}
// 验证JWT令牌的方法
public static boolean validateToken(String secreteKey, String token) {
Algorithm algorithm = Algorithm.HMAC512(secreteKey);
DecodedJWT jwt = JWT.require(algorithm)
.build()
.verify(token);
// 检查过期时间
return !jwt.getExpiresAt().before(new Date());
}
}
1万+

被折叠的 条评论
为什么被折叠?



