实现 jwt 鉴权- SpringBoot + 微服务

目录

项目结构

主要步骤

auth-service里:

1. 配置 pom.xml 依赖

2. 实现HandlerInterceptor 接口的 preHandle 函数

3. 实现 WebMvcConfigurer 的 addInterceptors 接口

4. 生成 token 和验证 token

5. 登录接口示例

user-service 里:

6. 实现拦截:以 user-service 为例


ps:项目源码等该项目课程答辩结束后会贴出,到时候可以看看源码会更清晰

项目结构

以 jwt 鉴权服务auth-service和 user-service 用户服务为例,auth-service 和 user-service 两个项目位于目录同级,项目结构如下

主要步骤

auth-service里:

1. 配置 pom.xml 依赖
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.0</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
    </dependencies>
2. 实现HandlerInterceptor 接口的 preHandle 函数
    • 注意加 @Component
    • preHandle 会拦截指定路径的请求,若验证成功返回了 return true ,然后该接口自己会再转发到对应接口处理请求,如果我们return false了就不会继续转发请求
package com.example.authservice.interceptors;

import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.example.authservice.utils.JWTUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Component
public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("*****************************************");
        System.out.println("开始token验证");
        System.out.println("*****************************************");
        Map<String, Object> map = new HashMap<>();
        // 获取请求头中令牌
        String token = request.getHeader("token");
        try {
            // 验证令牌
            JWTUtils.verify(token);
            System.out.println("*****************************************");
            System.out.println("token验证成功");
            System.out.println("*****************************************");
            return true;
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg","无效签名!");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","token过期!");
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
            map.put("msg","token算法不一致!");
        }catch (Exception e){
            e.printStackTrace();
            map.put("msg","token无效!!");
        }
        System.out.println("*****************************************");
        System.out.println("未通过token验证");
        System.out.println("*****************************************");
        // 未通过验证:设置状态
        map.put("state",false);
        // 将map转为json  jackson
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}
3. 实现 WebMvcConfigurer 的 addInterceptors 接口
  • 注册前面写的拦截器
    • 指定拦截路径 .addPathPatterns 和不拦截路径 .excludePathPatterns
  • 注意:
    • 拦截所有路径要用 /** ——两个*,不要写成一个了!!!
    • 记得加 @Configuration
  • 一般登录接口不拦截
    • 登录接口可以也写在 auth-service 服务中,更方便
      • ps:我本来写在 user-service 里的,本地运行也没问题,但是当我 maven 打包时一直会出现找不到 auth-service 这个模块(具体是 login 接口需要调用JWTUtils 的接口进行 token 验证,这里一直报错找不到这个 import),可是我明明 user-service 里已经添加依赖了,试了网上方法都不行。于是放弃,直接将 login 接口写在 auth-service 里,就避免了在 user-service 里直接调用 suth-service 的接口,但还是需要添加 suth-service 依赖的,因为要实现请求拦截,后面也会说到,这个时候再 maven 打包就可以了,有点玄学在的、、、
package com.example.authservice.config;

import com.example.authservice.interceptors.JWTInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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 {
    @Autowired
    private JWTInterceptor jWTInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jWTInterceptor)
                .addPathPatterns("/user/**")
                .excludePathPatterns("/auth/login");
    }
}
4. 生成 token 和验证 token
  • 此处 SHA256 加密
  • getToken(Map<String,String> map)函数生成 token,代码注释写了,一个萝卜一个坑按需填空即可
  • 验证 token 合法性的函数照抄就好
package com.example.authservice.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

public class JWTUtils {
    private static final String SIGNATURE = "!@#$SGW^HDY*%G";

    /**
     * 生成token
     */
    public static String getToken(Map<String,String> map){
        // 默认7天过期
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,7);
        // 创建jwt builder
        JWTCreator.Builder builder = JWT.create();
        // 设置payload
        map.forEach(builder::withClaim);
        // 指定令牌过期时间
        return builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(SIGNATURE));
    }

    /**
     * 验证token合法性
     */
    public static DecodedJWT verify(String token){
        return JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
    }
}

5. 登录接口示例

写在 auth-service 里,主要逻辑就是在 controller 层,示例如下

package com.example.authservice.controller;

import com.example.authservice.utils.JWTUtils;
import com.example.authservice.service.AuthService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.HashMap;
import java.util.Map;

@Api(tags = {"登录鉴权接口文档"})
@RestController
@RequestMapping("/auth")
@EnableSwagger2
public class AuthController {

    @Autowired
    private AuthService authService;

    @PostMapping("/login")
    @ResponseBody
    public Map<String,Object> login(String SID, String SPassword) {
        Map<String, Object> result = new HashMap<>();
        if(authService.login(SID, SPassword)){
            Map<String, String> payLoad = new HashMap<>();
            payLoad.put("id", SID);
            String token = JWTUtils.getToken(payLoad);
            result.put("token", token);
            result.put("state", true);
            result.put("msg", "登录成功!");
        }
         else {
            result.put("state","false");
            result.put("msg", "登录失败!");
        }
        return result;
    }
}

user-service 里:

6. 实现拦截:以 user-service 为例

要实现拦截需要以下步骤:

  • user-service 的 pom.xml 里配置 auth-service 依赖
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--JWT-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.0</version>
        </dependency>

        <!-- 添加对authservice模块的依赖 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>auth-service</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!-- 排除继承自authservice模块的该依赖,否则会冲突-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


    </dependencies>
  • 服务启动类上把 auth-service 加上,这样才能扫描到这个包,但是注意,@SpringBootApplication 本来是默认扫描该启动类对应的包的,如果加了指定扫描包选项,那么也要把这个启动类自己对应的那个包写上,不然自己都扫描不到了,即:
@SpringBootApplication(scanBasePackages={"com.example.userservice", "com.example.authservice"})

参考:

jwt 鉴权参考:

深入浅出JWT的token鉴权机制_jwtutils.token_header-CSDN博客

FrameWork/springbootjwt at master · EamonHu/FrameWork · GitHub

拦截器不起作用看这篇:

Spring Boot 拦截器无效,不起作用_判断拦截器是否起作用-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/528273.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Netty NioEventLoop详解

文章目录 前言类图主要功能NioEventLoop如何实现事件循环NioEventLoop如何处理多路复用Netty如何管理Channel和Selector管理Channel管理Selector注意事项 前言 Netty通过事件循环机制(EventLoop)处理IO事件和异步任务&#xff0c;简单来说&#xff0c;就是通过一个死循环&…

信息泄露漏洞的JS整改方案

引言 &#x1f6e1;️ 日常工作中&#xff0c;我们经常会面临线上环境被第三方安全厂商扫描出JS信息泄露漏洞的情况&#xff0c;这给我们的系统安全带来了潜在威胁。但幸运的是&#xff0c;对于这类漏洞的整改并不复杂。本文将介绍几种可行的整改方法&#xff0c;以及其中一种…

【C语言】:枚举和联合体

这里写自定义目录标题 1、枚举1.1 枚举类型的声明1.2 枚举类型的优点1.3 枚举类型的使用 2、联合体&#xff08;共用体&#xff09;2.1 联合体类型的声明2.2 联合体的特点2.3联合体大小的计算 1、枚举 1.1 枚举类型的声明 枚举顾名思义就是⼀⼀列举&#xff0c;把可能的取值⼀…

Tomcat以服务方式启动,无法访问网络共享目录问题

关于“Tomcat以服务方式启动&#xff0c;无法访问网络共享目录问题”解决方式如下&#xff1a; 1、通过doc命令【services.msc】打开本地服务找到&#xff0c;找到tomcat服务所在位置 2、右键打开Tomcat服务的属性 3、选择 登陆选项卡 4、选择“此账户”选项&#xff0c;并…

Nginx配置文件修改结合内网穿透实现公网访问多个本地web站点

文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 1. 下载windows版Nginx 进入官方网站(http://nginx.org/en/download.html)下载windows版的nginx 下载好后解压进入nginx目…

自动驾驶中的多目标跟踪_第二篇

自动驾驶中的多目标跟踪:第二篇 上一节介绍了多目标跟踪的定义、应用场景和类型以及面临的挑战&#xff1b;在这一节&#xff0c;我们回顾贝叶斯滤波&#xff0c;简单介绍运动模型和量测模型&#xff0c;卡尔曼滤波等。 附赠自动驾驶学习资料和量产经验&#xff1a;链接 贝叶…

Spring事务简介,事务角色,事务属性

1.Spring事务简介 事务作用&#xff1a;在数据层保障一系列的数据库操作同成功同失败Spring事务作用&#xff1a;在数据层或业务层保障一系列的数据操作同成功同失败 public interface PlatformTransactionManager{void commit(TransactionStatus status) throws TransactionE…

macU盘在电脑上读不出来 u盘mac读不出来怎么办 macu盘不能写入 Tuxera NTFS for Mac免费下载

对于Mac用户来说&#xff0c;使用U盘是很常见的操作&#xff0c;但有时候可能会遇到Mac电脑无法读取U盘的情况&#xff0c;这时候就需要使用一些特定的工具软件来帮助我们解决问题。本文就来告诉大家macU盘在电脑上读不出来是怎么回事&#xff0c;u盘mac读不出来怎么办。 一、m…

PaddleVideo:onnx模型导出

本文节介绍 PP-TSM 模型如何转化为 ONNX 模型&#xff0c;并基于 ONNX 引擎预测。 1&#xff1a;环境准备 安装 Paddle2ONNX python -m pip install paddle2onnx 安装 ONNXRuntime # 建议安装 1.9.0 版本&#xff0c;可根据环境更换版本号 python -m pip install onnxrunti…

C语言——关于指针运算的例题分析

1.指针运算中关于 sizeof 和 strlen 的例题分析 1. sizeof(数组名)&#xff0c;这⾥的数组名表⽰整个数组&#xff0c;计算的是整个数组的⼤⼩。 2. &数组名&#xff0c;这⾥的数组名表⽰整个数组&#xff0c;取出的是整个数组的地址。 3. 除此之外所有的数组名都表⽰…

【算法每日一练]-动态规划(保姆级教程 篇17 状态压缩)

目录 今日知识点&#xff1a; 把状态压缩成j,dp每行i的布置状态&#xff0c;从i-1和i-2行进行不断转移 把状态压缩成j,dp每行i的布置状态&#xff0c;从i-1行进行状态匹配&#xff0c;然后枚举国王数转移 POJ1185&#xff1a;炮兵阵地 思路&#xff1a; 题目&#xff1a;互…

互联网大厂ssp面经之路:计算机网络part2

什么是 HTTP 和 HTTPS&#xff1f;它们之间有什么区别&#xff1f; a. HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全超文本传输协议&#xff09;是用于在Web上传输数据的协议。它们之间的区别在于安全性和数据传输方式。 b. HTTP是一种不安全的协议&…

算法训练营第二十一天(二叉树part7)

算法训练营第二十一天&#xff08;二叉树part7&#xff09; 530.二叉搜索树的最小绝对差 力扣题目链接(opens new window) 题目 给你一棵所有节点为非负值的二叉搜索树&#xff0c;请你计算树中任意两节点的差的绝对值的最小值。 示例&#xff1a; 提示&#xff1a;树中至…

原来进制题如此简单

进制相关 二进制数与其他进制数之间的转化 二进制数转其他进制数&#xff08;十进制数除外&#xff09;一般不能直接转化&#xff0c;一般需要过度至十进制数&#xff0c;再转化为其他进制数。同理&#xff0c;其他进制数&#xff08;十进制数除外&#xff09;转二进制数也需过…

flutter多入口点entrypoint

native中引擎对象本身消耗内存(每个引擎对象约莫消耗42MB内存) 多引擎&#xff1a;native多引擎>启动>flutter多入口点entrypoint>多main函数>多子包元素集>多(子)程序 单引擎(复用)&#xff1a;native单引擎>复用启动>flutter多入口点entrypoint>多m…

error:LNK2005 已经在*.obj中定义 的原因分析及对策

LNK2005是一个重复定义错误&#xff0c;造成LNK2005主要有以下几种情况&#xff1a; 目录 全局变量的重复定义 情况A&#xff1a;全局变量在.cpp文件中的多次声明 情况B&#xff1a;变量名重复 头文件的包含重复 解决方案 #ifndef标识符宏定义 pragma once预编译 头文件…

使用yml文件配置python日志

新建一个logging.yml文件&#xff0c;内容如下&#xff1a; logging库提供了多个组件&#xff1a;Logger、Handler、Filter、Formatter&#xff1a; Logger 对象提供应用程序可直接使用的接口&#xff0c;供应用代码使用&#xff1b; Handler 发送日志到适当的目的地&#xff…

PMC管理中落实生产作业计划的思路与方法

在快节奏的现代商业环境中&#xff0c;PMC&#xff08;生产及物料控制&#xff09;管理对于确保企业生产流程的高效运转至关重要。生产作业计划的落实不仅关乎企业的生产效率和成本控制&#xff0c;更是企业竞争力的重要体现。那么&#xff0c;PMC管理中如何有效落实生产作业计…

上传应用程序到苹果应用商店的工具和要点

引言 在今天的移动应用市场中&#xff0c;将应用程序上传到苹果应用商店&#xff08;App Store&#xff09;是许多开发者的首要任务之一。然而&#xff0c;不同操作系统下的开发者可能需要使用不同的工具和遵循不同的要求来完成这一任务。本文将介绍在 macOS、Windows 和 Linu…

【C语言】:字符函数和字符串函数

这里写目录标题 1、strlen的使用和模拟实现2、strcpy的使用和模拟3、strcat 的使用和模拟实现4、strcmp 的使用和模拟实现5、strncpy 函数的使用6、strncat 函数的使用7、strncmp函数的使用8、strstr 的使用和模拟实现9、strtok 函数的使用10、strerror 函数的使用11、字符分类…