服务网关(Gateway)自定义全局过滤器&统一Token处理

网关登录校验

        在网关工程中添加全局过滤器

import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.model.vo.AuthInfo;
import com.xuecheng.commons.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.SneakyThrows;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;

/**
 * 网关-全局过滤器
 * 1、实现两个接口和两个方法
 * 2、在filter方法中,完成过滤逻辑
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    /**
     * 核心过滤方法:业务处理
     * @param exchange:请求上下文(获取request和response)
     * @param chain:过滤器链(控制程序放行)
     * @return
     */
    @SneakyThrows
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //1、获取当前的请求连接
        String path = request.getURI().getPath();
        //2、判断,此请求地址是否需要进行token校验,如果不需要,直接放行,进入微服务
        if(path.contains("coursePub/preview") ||
                path.contains("login") ||
                path.contains("basic/dictionary") ||
                path.contains("category/tree-nodes")||
                path.contains("course/upload")||
                path.contains("search/")){
            return chain.filter(exchange);
        }
        //3、获取请求头参数token
        String token = request.getHeaders().getFirst("Authorization");
        Boolean verifyToken = JwtUtils.verifyToken(token);
        //4、验证token是否合法,如果不合法,响应状态码401
        if(!verifyToken) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete(); //直接返回
        }
        //5、解析token,获取登录时存入的数据(userId,companyId,companyName)
        Claims claims = JwtUtils.parserToken(token).getBody();
        Long userId = claims.get("userId", Long.class);
        Long companyId = claims.get("companyId", Long.class);
        String companyName = claims.get("companyName", String.class);
        //转化java对象
        AuthInfo info = new AuthInfo();
        info.setUid(userId);
        info.setCompanyName(companyName);
        info.setCompanyId(companyId);
        //6、设置一个新的请求头参数(解析后的明文数据)
        String json = URLEncoder.encode(JSON.toJSONString(info),"UTF-8");
        //创建一个httpRequest的请求对象
        ServerHttpRequest httpRequest = request.mutate().headers(httpHeaders -> {
            httpHeaders.set("payload", json);
        }).build();
        //将此请求对象,写入到微服务转发的上下文中
        exchange.mutate().request(httpRequest);
        return chain.filter(exchange);
    }

    /**
     * 指定多个过滤器时,此过滤器的执行顺序
     */
    public int getOrder() {
        return 0;
    }
}

统一token解析(添加到微服务当中或提取出来)

        编写拦截器

import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.model.vo.AuthInfo;
import com.xuecheng.commons.utils.AuthInfoHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;

/**
 * 自定义拦截器
 */
@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

    //进入controller方法之前执行。
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1、获取网关转发来的json数据,
        String payload = request.getHeader("payload");
        if(StringUtils.isEmpty(payload)) {
            return true; //执行controller
        }
        //2、转化成AuthInfo对象,
        String  json = URLDecoder.decode(payload, "UTF-8");
        log.info("json = " + json);
        AuthInfo info = JSON.parseObject(json, AuthInfo.class);
        log.info("info = " + info);
        //3、存入threadlocal
        AuthInfoHolder.setAuthInfo(info);
        return true;
    }

    //执行controller方法之后执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    //响应结束之前
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

       

        配置拦截器

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//配置类,注册拦截器
@Configuration
public class InterceptorConfig  implements WebMvcConfigurer {

    //注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenInterceptor())  // 添加拦截器
                .addPathPatterns("/**");    // 添加拦截的路径
    }
}

        ThreadLocal工具类

import com.xuecheng.commons.model.vo.AuthInfo;

/**
 * 存放用户id的容器
 */
public class AuthInfoHolder {

    private final static ThreadLocal threadLocal = new ThreadLocal<>();

    /**
     * 获取线程中的用户
     */
    public static AuthInfo getAuthInfo() {
        return threadLocal.get();
    }

    /**
     * 设置当前线程中的用户
     */
    public static void setAuthInfo(AuthInfo info) {
        threadLocal.set(info);
    }

    public static Long getUserId() {
        return threadLocal.get().getUid();
    }

    public static Long getCompanyId() {
        if(threadLocal.get() != null) {
            return threadLocal.get().getCompanyId();
        }else {
            return null;
        }
    }

    public static void remove(){threadLocal.remove();}

}

你可能感兴趣的:(gateway,java,开发语言)