用户认证与spring cloud gateway网关整合

思路

所有请求都会经过服务网关,服务网关对外暴露服务,在网关进行统一用户认证;
既然要在网关进行用户认证,网关得知道对哪些url进行认证,所以我们得对ur制定规则
Api接口异步请求的,我们采取url规则匹配,如:/api//auth/,如凡是满足该规则的都必须用户认证

在服务网关中加上过滤器,过滤请求,进行认证请求

对下面Filter代码进行解释:

用户登录后,返回通过jwt生成的token,返回个前端,在token的有效时间内,用户访问需要认证的接口时,通过getUserId,拿到token中的用户id,如果不为null,则通过认证,如果为null则返回错误异常

/**
 * 全局Filter,统一处理会员登录与外部不允许访问的服务
 * <p>
 * 创建时间: 2022-03-21 19:07
 *
 * @author fuxshen
 * @version v1.0.0
 * @since v1.0.0
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
    

	private AntPathMatcher antPathMatcher = new AntPathMatcher();

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
		ServerHttpRequest request = exchange.getRequest();
		String path = request.getURI().getPath();
		System.out.println("==="+path);

		//内部服务接口,不允许外部访问
		if(antPathMatcher.match("/**/inner/**", path)) {
    
    
			ServerHttpResponse response = exchange.getResponse();
			return out(response, ResultCodeEnum.PERMISSION);
		}

		//api接口,异步请求,校验用户必须登录
		if(antPathMatcher.match("/api/**/auth/**", path)) {
    
    
			Long userId = this.getUserId(request);
			if(StringUtils.isEmpty(userId)) {
    
    
				ServerHttpResponse response = exchange.getResponse();
				return out(response, ResultCodeEnum.LOGIN_AUTH);
			}
		}
		return chain.filter(exchange);
	}

	@Override
	public int getOrder() {
    
    
		return 0;
	}

	/**
	 * api接口鉴权失败返回数据
	 * @param response
	 * @return
	 */
	private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
    
    
		Result result = Result.build(null, resultCodeEnum);
		byte[] bits = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
		DataBuffer buffer = response.bufferFactory().wrap(bits);
		//指定编码,否则在浏览器中会中文乱码
		response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
		return response.writeWith(Mono.just(buffer));
	}

	/**
	 * 获取当前登录用户id
	 * @param request
	 * @return
	 */
	private Long getUserId(ServerHttpRequest request) {
    
    
		String token = "";
		List<String> tokenList = request.getHeaders().get("token");
		if(null  != tokenList) {
    
    
			token = tokenList.get(0);
		}
		if(!StringUtils.isEmpty(token)) {
    
    
			return JwtHelper.getUserId(token);
		}
		return null;
	}
}

jwt工具类
:此工具类主要用于生成token

/**
 * jwt工具类
 * <p>
 * 创建时间: 2022-03-20 17:14
 *
 * @author fuxshen
 * @version v1.0.0
 * @since v1.0.0
 */
public class JwtHelper {
    
    
	//token的过期时间
	private static long tokenExpiration = 24 * 60 * 60 * 1000;
	//token签名秘钥
	private static String tokenSignKey = "123456";

	/**
	 * 根据参数生成token
	 *
	 * @param userId
	 * @param userName
	 * @return java.lang.String
	 * @Description
	 * @author fuxshen
	 * @date 2022-03-20 17:17:15
	 **/
	public static String createToken(Long userId, String userName) {
    
    
		String token = Jwts.builder()
				.setSubject("YYGH-USER")
				//设置过期时间(当前系统时间+设置的时间) 当前系统时间,往后延迟我们设置的时间
				.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
				//加密的主体信息
				.claim("userId", userId)
				.claim("userName", userName)
				//签名hash
				.signWith(SignatureAlgorithm.HS512, tokenSignKey)
				.compressWith(CompressionCodecs.GZIP).compact();
		return token;
	}


	/**
	 * 根据token字符串,得到用户id
	 *
	 * @param token
	 * @return java.lang.Long
	 * @Description
	 * @author fuxshen
	 * @date 2022-03-20 17:18:15
	 **/
	public static Long getUserId(String token) {
    
    
		if (StringUtils.isEmpty(token)) return null;
		Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
		Claims claims = claimsJws.getBody();
		Integer userId = (Integer) claims.get("userId");
		return userId.longValue();
	}


	/**
	 * 根据token字符串,得到用户名称
	 *
	 * @param token
	 * @return java.lang.String
	 * @Description
	 * @author fuxshen
	 * @date 2022-03-20 17:19:01
	 **/
	public static String getUserName(String token) {
    
    
		if (StringUtils.isEmpty(token)) return "";
		Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
		Claims claims = claimsJws.getBody();
		return (String) claims.get("userName");
	}

	public static void main(String[] args) {
    
    
		String token = JwtHelper.createToken(1L, "55");
		System.out.println(token);
		System.out.println(JwtHelper.getUserId(token));
		System.out.println(JwtHelper.getUserName(token));
	}
}

状态码返回的枚举类型
:下面枚举可根据业务需要自定定义

/**
 * 统一返回结果状态信息枚举
 * <p>
 * 创建时间: 2022-02-09 14:50
 *
 * @author v_fuxshen
 * @version v1.0.0
 * @since v1.0.0
 */
@Getter
public enum  ResultCodeEnum {
    
    
	LOGIN_AUTH(208, "未登陆"),
	PERMISSION(209, "没有权限"),

	private Integer code;
	private String message;

	private ResultCodeEnum(Integer code, String message) {
    
    
		this.code = code;
		this.message = message;
	}
}

如果需要整合前端下面是前端内容

import axios from 'axios'
import {
    
     MessageBox, Message } from 'element-ui'
import cookie from 'js-cookie'

// 创建axios实例
const service = axios.create({
    
    
  baseURL: 'http://localhost',
  timeout: 15000 // 请求超时时间
})

// http request 拦截器
service.interceptors.request.use(
  config => {
    
    
    //判断cookie是否有token值
    if (cookie.get('token')) {
    
    
      //token值放到cookie里面
      config.headers['token'] = cookie.get('token')
    }
    return config
  },
  err => {
    
    
    return Promise.reject(err)
  })
// http response 拦截器
service.interceptors.response.use(
  response => {
    
    
    //状态码是208
    if (response.data.code === 208) {
    
    
      //弹出登录输入框
      eventLogin.$emit('loginDialogEvent')
      return
    } else {
    
    
      if (response.data.code !== 200) {
    
    
        Message({
    
    
          message: response.data.message,
          type: 'error',
          duration: 5 * 1000
        })
        return Promise.reject(response.data)
      } else {
    
    
        return response.data
      }
    }
  },
  error => {
    
    
    return Promise.reject(error.response)
  })
export default service

猜你喜欢

转载自blog.csdn.net/qq_51726114/article/details/123644033