微服务项目构建鉴权中心(网关统一鉴权)

一、项目准备

  1. 父项目,pom.xml,见微服务项目构建认证中心

  2. 子项目,pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>hg_blog</artifactId>
            <groupId>com.jiangming</groupId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>hegu-gateway-service9527</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>com.jiangming</groupId>
                <artifactId>hegu-api-commons</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    
            <!--gateway-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.9.1</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
    </project>
    
  3. 项目结构

    在这里插入图片描述

  4. nacos配置文件

    spring:
      cloud:
        gateway:
          #跨域设置
          globalcors:
            cors-configurations:
              '[/**]':
                allowedOrigins: "*"
                allowedHeaders: "*"
                allowCredentials: true
                allowedMethods:
                  - GET
                  - POST
                  - PUT
                  - DELETE
    
          discovery:
            locator:
              enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由转发
          routes:
          	#id唯一
            - id: hegu-auth-jwt
              #资源
              uri: lb://hegu-auth-jwt
              #断言
              predicates:
                - Path=/login
    

二、代码

  1. application.yml

    spring:
      profiles:
        active: dev
    
  2. bootstrap.yml

    server:
      port: 9527
    
    spring:
      application:
        name: hegu-gateway-service
      cloud:
        nacos:
          discovery:
            server-addr: nacos地址
            #命名空间
            namespace: ce58f19d-b36c-4aad-968a-1a1f2280cfc
          config:
            server-addr: nacos地址
            #命名空间
            namespace: ce58f19d-b36c-4aad-968a-1a1f2280cfc
            file-extension: yaml
    
  3. HeguGatewayServiceMain启动类

    package com.jc.springcloud;
    
    /**
     * @program: hg_blog
     * @description:
     * @author: hjc
     * @create: 2022-01-04 19:19
     **/
    @SpringBootApplication
    @EnableDiscoveryClient
    public class HeguGatewayServiceMain {
        public static void main(String[] args){
            SpringApplication.run(HeguGatewayServiceMain.class,args);
        }
    }
    
    
  4. JwtUtil

    package com.jc.springcloud.util;
    
    /**
     * @program: hg_blog
     * @description: token校验类
     * @author: hjc
     * @create: 2022-01-05 14:54
     **/
    public class JwtUtil {
    
        private static final String JWT_PAYLOAD_USER_KEY = "user";
    
        // 公钥,RSA在线生成工具生成私钥对应的公钥
        private static final String PUBLIC_KEY = "";
    
        /***
         * @description 公钥
         * @return java.security.PublicKey
         * @author hjc
         * CreateDate 2022/1/5 15:14
         */
        public static PublicKey getPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
            X509EncodedKeySpec spec = new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(PUBLIC_KEY));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(spec);
        }
    
        public static <T> T getPayLoadFromToken(String token,PublicKey publicKey,Class<T> claType) {
            Claims claims = Jwts.parser()//获得JWT解析器的编译器对象
                    .setSigningKey(publicKey)//设置签名(公钥加密签名)
                    .parseClaimsJws(token)//解析token获得JWS对象
                    .getBody();
            return JSON.parseObject(claims.get(JWT_PAYLOAD_USER_KEY).toString(),claType);
        }
    }
    
  5. ResourceUtil

    package com.jc.springcloud.util;
    
    /**
     * @program: hg_blog
     * @description: 资源分配类
     * @author: hjc
     * @create: 2022-01-05 16:54
     **/
    @Slf4j
    @Component
    public class ResourceUtil {
    
        //公共资源
        private static final String[] PUBLIC_PATH = {
                "/login",
        };
    
        //用户资源
        private static final String[] USER_PATH = {
           
        };
    
        //管理员资源
        private static final String[] ADMIN_PATH = {
                
        };
    
        private static final String AUTH_USER = "ROLE_USER";
        private static final String AUTH_ADMIN = "ROLE_ADMIN";
    
        /***
         * @description 获取公共资源
         * @return java.util.List<java.lang.String>
         * @author hjc
         * CreateDate 2022/1/5 17:13
         */
        public List<String> getPublicPath(){
            List<String> path = new ArrayList<>();
            Collections.addAll(path,PUBLIC_PATH);
            return path;
        }
    
        public List<String> getPath(String auth){
            List<String> path = new ArrayList<>();
            if (AUTH_USER.equals(auth)){
                log.info("获取用户权限!");
                Collections.addAll(path,USER_PATH);
            }else if (AUTH_ADMIN.equals(auth)){
                log.info("获取管理员权限!");
                Collections.addAll(path,ADMIN_PATH);
            }
            return path;
        }
    
        /***
         * @description 判断资源是否匹配
         * @param requestPath 获取路径
         * @param path 访问的资源
         * @return boolean
         * @author hjc
         * CreateDate 2022/1/5 17:49
         */
        public boolean isResourcePath(String requestPath,List<String> path){
            return path.stream()
                    .map(url -> url.replace("/**",""))
                    .anyMatch(requestPath::startsWith);
        }
    }
    
  6. AuthorizeFilter

    package com.jc.springcloud.filter;
    
    /**
     * @program: hg_blog
     * @description: 鉴权过滤器 验证token
     * @author: hjc
     * @create: 2022-01-05 16:04
     **/
    @Slf4j
    @Component
    public class AuthorizeFilter implements GlobalFilter, Ordered {
    
        private static final String AUTHORIZE_TOKEN = "token";
    
        @Resource
        private ResourceUtil resourceUtil;
    
        @SneakyThrows
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
            //获取请求
            ServerHttpRequest request = exchange.getRequest();
            //获取响应
            ServerHttpResponse response = exchange.getResponse();
    
            //不需要权限的放行
            String requestPath = request.getURI().getPath();
            if (resourceUtil.isResourcePath(requestPath,resourceUtil.getPublicPath())){
                log.info("公共资源->"+requestPath);
                return chain.filter(exchange);
            }
    
            //获取请求头
            HttpHeaders headers = request.getHeaders();
    
            //获取token
            String token = headers.getFirst(AUTHORIZE_TOKEN);
            //判断请求头是否有令牌
            if (token == null || "".equals(token)){
                return unauthorized(response,"请登录!");
            }
            log.info("token->"+token);
    
            try{
                //解签token,获取payload
                Map<String,Object> payloadMap = JwtUtil.getPayLoadFromToken(token,JwtUtil.getPublicKey(),Map.class);
                //获取权限信息
                List<Map> auhtMap = (List<Map>) payloadMap.get("auth");
                List authList = new ArrayList<>();
                for (Map map : auhtMap){
                    authList.add(map.get("authority"));
                }
                int user_id = (int) payloadMap.get("user_id");
                String auth = (String) authList.get(0);
                if (!resourceUtil.isResourcePath(requestPath,resourceUtil.getPath(auth))){
                    return unauthorized(response,"权限不足!");
                }
    
                log.info("权限资源->"+requestPath);
                //将用户user_id放入header中发送给下游业务
                request.mutate().header("user_id", String.valueOf(user_id)).build();
    
                log.info(String.valueOf(user_id));
    
            }catch (ExpiredJwtException e){
                e.printStackTrace();
                return unauthorized(response,"登录过期,请重新登录!");
            }
    
            return chain.filter(exchange.mutate()
                    .request(request)
                    .build());
        }
    
        private Mono<Void> unauthorized(ServerHttpResponse response,String message){
            response.getHeaders().add(HttpHeaders.CONTENT_TYPE,"application/json;charset=UTF-8");
            //401
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            CommonResult result = CommonResult.fail(HttpStatus.UNAUTHORIZED.value(),message);
            DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
            return response.writeWith(Mono.just(dataBuffer));
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

三、测试

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁Mar.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值