zoukankan      html  css  js  c++  java
  • 我爱java系列之---【商城项目微服务鉴权代码实现(二)—JWT在项目中的应用案例】

    一、思路分析

    1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
    2. 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
    3. 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
    4. 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误

    二、代码实现

    1.系统微服务签发token

    (1)在changgou_service_system中创建类: JwtUtil

    /**
     * JWT工具类
     */
    public class JwtUtil {
    
        //有效期为
        public static final Long JWT_TTL = 3600000L;// 60 * 60 *1000  一个小时
        //设置秘钥明文
        public static final String JWT_KEY = "itcast";
    
        /**
         * 创建token
         * @param id
         * @param subject
         * @param ttlMillis
         * @return
         */
        public static String createJWT(String id, String subject, Long ttlMillis) {
    
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            if(ttlMillis==null){
                ttlMillis=JwtUtil.JWT_TTL;
            }
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            SecretKey secretKey = generalKey();
    
            JwtBuilder builder = Jwts.builder()
                    .setId(id)              //唯一的ID
                    .setSubject(subject)   // 主题  可以是JSON数据
                    .setIssuer("admin")     // 签发者
                    .setIssuedAt(now)      // 签发时间
                    .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                    .setExpiration(expDate);// 设置过期时间
            return builder.compact();
        }
    
        /**
         * 生成加密后的秘钥 secretKey
         * @return
         */
        public static SecretKey generalKey() {
            byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
            SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
            return key;
        }
    }

    (2)修改AdminController的login方法, 用户登录成功 则 签发TOKEN

        /**
         * 登录
         * @param admin
         * @return
         */
        @PostMapping("/login")
        public Result login(@RequestBody Admin admin){
            boolean login = adminService.login(admin);
            if(login){  //如果验证成功
                Map<String,String> info = new HashMap<>();
                info.put("username",admin.getLoginName());
                String token = JwtUtil.createJWT(UUID.randomUUID().toString(), admin.getLoginName(), null);
                info.put("token",token);
                return new Result(true, StatusCode.OK,"登录成功",info);
            }else{
                return new Result(false,StatusCode.LOGINERROR,"用户名或密码错误");
            }
        }

    使用postman 测试

    2.网关过滤器验证token

    (1)在changgou_gateway_system网关系统添加依赖

    <!--鉴权-->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>

    (2)创建JWTUtil类

    /**
     * jwt校验工具类
     */
    public class JwtUtil {
    
        //有效期为
        public static final Long JWT_TTL = 3600000L;// 60 * 60 *1000  一个小时
        //设置秘钥明文
        public static final String JWT_KEY = "itcast";
    
        /**
         * 生成加密后的秘钥 secretKey
         *
         * @return
         */
        public static SecretKey generalKey() {
            byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
            SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
            return key;
        }
    
        /**
         * 解析
         *
         * @param jwt
         * @return
         * @throws Exception
         */
        public static Claims parseJWT(String jwt) throws Exception {
            SecretKey secretKey = generalKey();
            return Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        }
    }

    (3)创建过滤器,用于token验证

    /**
     * 鉴权过滤器 验证token
     */
    @Component
    public class AuthorizeFilter implements GlobalFilter, Ordered {
        private static final String AUTHORIZE_TOKEN = "token";
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            //1. 获取请求
            ServerHttpRequest request = exchange.getRequest();
            //2. 则获取响应
            ServerHttpResponse response = exchange.getResponse();
            //3. 如果是登录请求则放行
            if (request.getURI().getPath().contains("/admin/login")) {
                return chain.filter(exchange);
            }
            //4. 获取请求头
            HttpHeaders headers = request.getHeaders();
            //5. 请求头中获取令牌
            String token = headers.getFirst(AUTHORIZE_TOKEN);
    
            //6. 判断请求头中是否有令牌
            if (StringUtils.isEmpty(token)) {
                //7. 响应中放入返回的状态吗, 没有权限访问
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //8. 返回
                return response.setComplete();
            }
    
            //9. 如果请求头中有令牌则解析令牌
            try {
                JwtUtil.parseJWT(token);
            } catch (Exception e) {
                e.printStackTrace();
                //10. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //11. 返回
                return response.setComplete();
            }
            //12. 放行
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }

    (4)测试:

    注意: 数据库中管理员账户为 : admin , 密码为 : 123456

    如果不携带token直接访问,则返回401错误

    如果携带正确的token,则返回查询结果

    愿你走出半生,归来仍是少年!
  • 相关阅读:
    多个tomcat配置,解决冲突问题
    多态-重载和覆载
    静态成员、静态类和枚举
    重复使用类--继承和组合
    建立更可靠的OOP程序-类和成员的访问控制
    用ps画一个Gif的小房子(1)
    在h5页面上添加音乐播放
    使用Object类为实例定义方法和属性
    使用 prototype 定义方法和属性
    使用 this 关键字定义方法和属性
  • 原文地址:https://www.cnblogs.com/hujunwei/p/11347931.html
Copyright © 2011-2022 走看看