服务网关Gateway实现用户鉴权_网关全局过滤器加入JWT鉴权

服务网关Gateway实现用户鉴权_什么是JWT?

服务网关Gateway实现用户鉴权_网关全局过滤器加入JWT鉴权_第1张图片

什么是JWT :

JWT是一种用于双方之间传递安全信息的简洁的、URL安全的声明规 范。定义了一种简洁的,自包含的方法用于通信双方之间以Json对 象的形式安全的传递信息。特别适用于分布式站点的单点登录 (SSO)场景.

 传统的session认证 每次提到无状态的 JWT 时相信都会看到另一种基于 Session 的用户 认证方案介绍,这里也不例外,Session 的认证流程通常会像这 样: 

服务网关Gateway实现用户鉴权_网关全局过滤器加入JWT鉴权_第2张图片

 缺点

  • 安全性:CSRF攻击因为基于cookie来进行用户识别, cookie如果被截获,用户就会很容易受 到跨站请求伪造的攻击。
  • 扩展性:对于分布式应用,需要实现 session 数据共享
  • 性能:每一个用户经过后端应用认证之后,后端应用都要在服务端做一次记录,以方便用户 下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开 销会明显增大,与REST风格不匹配。因为它在一个无状态协议里注入了状态。

JWT方式

服务网关Gateway实现用户鉴权_网关全局过滤器加入JWT鉴权_第3张图片

优点

  • 无状态
  • 适合移动端应用
  • 单点登录友好 

配置跳过验证路由yml文件配置

org:
 my:
   jwt:
      #跳过认证的路由
     skipAuthUrls:
         - /user/login

创建Response相应类

@Data
public class Response {
    //响应状态码
    private Integer code;
    //相应信息
    private String message;


    public Response(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Response() {

    }


}

创建JWT工具类JWTUtils

public class JWTUtil {
    // 秘钥
    public static final String SECRET_KEY =
"erbadagang-123456";
    // token过期时间
    public static final long
TOKEN_EXPIRE_TIME = 5 * 60 * 1000;
    // 签发人
    private static final String ISSUER =
"issuer";
    // 用户名
    private static final String USER_NAME =
"username";
    
}
//生成签名方法
public static String token(String
username) {
Date now = new Date();
        //SECRET_KEY是用来加密数据签名秘钥
        Algorithm algorithm =
Algorithm.HMAC256(SECRET_KEY);
        String token = JWT.create()
                // 签发人
               .withIssuer(ISSUER)
                // 签发时间
               .withIssuedAt(now)
                // 过期时间
               .withExpiresAt(new
Date(now.getTime() + TOKEN_EXPIRE_TIME))
                // 保存权限标记
               .withClaim(USER_NAME,
username)
               .sign(algorithm);
        log.info("jwt generated user={}",
username);
        return token;
   }
//验证签名
public static boolean verify(String token)
{
        try {
            //SECRET_KEY是用来加密数据签名秘钥
            Algorithm algorithm =
Algorithm.HMAC256(SECRET_KEY);
            JWTVerifier verifier =
JWT.require(algorithm)
                   .withIssuer(ISSUER)
                   .build();
            //如果校验有问题会抛出异常。
            verifier.verify(token);
            return true;
       } catch (Exception ex) {
            ex.printStackTrace();
       }
        return false;
   }

创建LoginGlobalFilter全局过滤器

@Data
@Slf4j
@Component
@ConfigurationProperties("org.my.jwt")
public class LoginGlobalFilter  implements
GlobalFilter, Ordered {
    // 跳过路由数组
    private String[] skipAuthUrls;
    @Override
public Mono
filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
        //获取请求url地址
        String url =
exchange.getRequest().getURI().getPath();
        //跳过不需要验证的路径
        if (null != skipAuthUrls &&
isSkipUrl(url)) {
            return chain.filter(exchange);
       }
        //从请求头中取得token
        String token =
exchange.getRequest().getHeaders().getFirst(
"Authorization");
        if (StringUtils.isEmpty(token)) {
            return
createResponseObj(exchange,500,"token参数缺
失");
       }
        //请求中的token是否有效
        boolean verifyResult =
JWTUtil.verify(token);
        if (!verifyResult) {
            return
createResponseObj(exchange,500,"token 失效");
       }
//如果各种判断都通过,执行chain上的其他业
务逻辑
        return chain.filter(exchange);
   }
    @Override
    public int getOrder() {
        return 0;
   }
    /**
     * 判断当前访问的url是否开头URI是在配置的忽略
url列表中
     *
     * @param url
     * @return
     */
    public boolean isSkipUrl(String url) {
        for (String skipAuthUrl :
skipAuthUrls) {
            if (url.startsWith(skipAuthUrl))
{
                return true;
           }
       }
        return false;
   }
    // 组装返回数据
  private Mono
createResponseObj(ServerWebExchange
exchange,Integer code,String message){
        ServerHttpResponse response =
exchange.getResponse();
        // 设置响应状态码200
      
response.setStatusCode(HttpStatus.OK);
        // 设置响应头
        response.getHeaders().add("ContentType", "application/json;charset=UTF-8");
        // 创建响应对象
        Response res = new Response(code,
message);
        // 把对象转成字符串
        byte[] responseByte =
JSONObject.toJSONString(res).toString().getB
ytes(StandardCharsets.UTF_8);
        DataBuffer buffer =
response.bufferFactory().wrap(responseByte);
        return
response.writeWith(Flux.just(buffer));
   }
}

测试

服务网关Gateway实现用户鉴权_网关全局过滤器加入JWT鉴权_第4张图片 

 

你可能感兴趣的:(gateway,网络,运维)