欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

使用Gateway进行JWT身份验证的方法

最编程 2024-07-28 12:04:07
...

思路: 全局过滤器对所有的请求拦截(登录请求放行)然后校验token,(token中带有用户信息,如果和当前的用户信息匹配的话就放行)

1- 引入相关jar

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
</dependency>

2- 编写Jwt工具类(生成token + 解析token)

package spring.cloud.gateway.common;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.springframework.util.StringUtils;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import spring.cloud.gateway.exception.PermissionException;

public class JwtUtil {
    public static final String SECRET = "qazwsx123444$#%#()*&& asdaswwi1235 ?;!@#kmmmpom in***xx**&";
    public static final String TOKEN_PREFIX = "Bearer";
    public static final String HEADER_AUTH = "Authorization";

    public static String generateToken(String user,String pwd) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", new Random().nextInt());
        map.put("user", user);
    //设置失效时间?
        String jwt = Jwts.builder()
                .setSubject("user info").setClaims(map)
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        String finalJwt = TOKEN_PREFIX + " " +jwt;
        return finalJwt;
    }

    public static Map<String,String> validateToken(String token) {
        if (token != null) {
            HashMap<String, String> map = new HashMap<String, String>();
            Map<String,Object> body = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                    .getBody();
            String id =  String.valueOf(body.get("id"));
            String user = (String) (body.get("user"));
            // todo 获取user和id之后可以结合数据库?或者请求中的user信息? 对用户做校验 -ps 如何判断用户是否窃取别人的token呢?
            map.put("id", id);
            map.put("user", user);
            if(StringUtils.isEmpty(user)) {
                throw new PermissionException("user is error, please check");
            }
            return map;
        } else {
            throw new PermissionException("token is error, please check");
        }
    }

}

3- 添加GlobalFilter

package spring.cloud.gateway.filter;

import java.net.URI;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import spring.cloud.gateway.common.JwtUtil;
import spring.cloud.gateway.exception.PermissionException;

@Component
public class AuthFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        Route gatewayUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        URI uri = gatewayUrl.getUri();
        ServerHttpRequest request = (ServerHttpRequest)exchange.getRequest();
        HttpHeaders header = request.getHeaders();
        String token = header.getFirst(JwtUtil.HEADER_AUTH);

        // TODO 没有携带token的则判断URL,若是访问登录接口则放行,其他的则返回错误码,提示登录
        passLogin(request, token);

        Map<String,String> userMap = JwtUtil.validateToken(token);
        ServerHttpRequest.Builder mutate = request.mutate();
        if(userMap.get("user").equals("admin") || userMap.get("user").equals("spring") || userMap.get("user").equals("cloud")) {
            mutate.header("x-user-id", userMap.get("id"));
            mutate.header("x-user-name", userMap.get("user"));
            //x-user-serviceName 表示下游请求对应的服务名如 SPRING-CLOUD-SERVICE  SPRING-CLOUD-GATEWAY
            mutate.header("x-user-serviceName", uri.getHost());
        }else {
            throw new PermissionException("user not exist, please check");
        }
        ServerHttpRequest buildReuqest =  mutate.build();
        return chain.filter(exchange.mutate().request(buildReuqest).build());
    }

    /**
     * 对于没有携带token的,且是访问登录接口的请求,不做认证,直接执行登录操作
     * @param request
     * @param token
     */
    private void passLogin(ServerHttpRequest request, String token) {
        if (StringUtils.isBlank(token)) {
            PathContainer pathContainer = request.getPath().pathWithinApplication();
            String value = pathContainer.value();
            List<PathContainer.Element> elements = pathContainer.elements();
            int getToken = value.indexOf("getToken");
            //若是访问登录接口则放行
            if (getToken > 0) {
                int end = value.lastIndexOf("/");
                String name = value.substring(getToken + "getToken".length() + 1, end);
                String admin = JwtUtil.generateToken(name, "123");
                throw new PermissionException("please login to get the token:" + admin);
            }
        }
    }
}

推荐阅读