当前位置: 首页 > news >正文

springboot+vue2集成JWT token实现权限验证

前端项目搭建参考:

Vue项目的搭建和启动_vue项目启动 csdn-CSDN博客

Vue + ElementUI 登录页面_vue用户登录页面-CSDN博客

跨域问题前端解决-CSDN博客

实现思路:

1. 实现的目的:为了保护网站安全信息,使用jwt进行权限验证,也就是说只有登录用户才可以看到网站的一些特定内容。那么浏览器每次发起请求时,就需要带上携带加密登录用户信息的token令牌。而token是用户登录时后端返回给前端的。

2. 编写登录接口,传入的登录form表单跟数据库储存的数据一致时,接口返回给前端之前,生成一个token,跟着登录信息一起返回

3. 前端拿到从服务端返回的token,储存于localStorage中,然后在前端配置发起请求时统一的拦截器,在请求头中塞入这个token,这样每个请求就都携带了token

4. 后端这个时候就需要校验了,你这个请求想要查看我网站的安全信息,我得先看看你有没有相应用户的权限,是否之前登录过,这个依据就是是否携带了正确的token。后端需要对大多数请求都进行这个校验,而每个请求的校验逻辑是一样的,所以后端需要写一个拦截器,拦截所有的请求,只有检验你是带着正确的token来的,才可以访问资源,当然登录接口需要放开。

5. 最后还需要在前端的接收请求拦截器中,当某个请求没有权限,即返回code=401时,需要跳转到登录页面引导用户登录或者注册。

1. pom文件添加JWT依赖

<!--jwt-->
<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>${jwt-version}</version>
</dependency>

2. 生成token,在登录接口返回给前端

/**
     * 生成token
     * @param userId 账号
     * @param sign 密码
     * @return String
     */
    public static String getToken(String userId, String sign) {
        return JWT.create().withAudience(userId) //将userId荷载
                .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) //当前时间2小时后过期
                .sign(Algorithm.HMAC256(sign));  //password作为token的密钥
    }
@RestController
public class LoginController {

    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public Result<JSONObject> login(@RequestBody User user) {
        Result<JSONObject> result = new Result<JSONObject>();
        if (StrUtil.isBlank(user.getUserName()) || StrUtil.isBlank(user.getPassword())) {
            return Result.error("数据输入不合法");
        }
        User dbUser = userService.login(user);
        //生成token
        String token = TokenUtils.getToken(user.getUserName(), user.getPassword());
        JSONObject obj = new JSONObject();
        obj.set("user", dbUser);
        obj.set("token", token);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }
}

 3. 前端将token存入localStorage,设置请求拦截器,给每个请求带上token

submitForm() {
      this.$refs.form.validate((valid) => {
          if (valid) {
            let loginUrl = '/login'
            postAction(loginUrl, this.form).then((res) => {
              if (res.success) {
                let token = res.result.token;
                localStorage.setItem("token", token)
                this.$message.success("登录成功!")
                router.push("/")

              }
            })
          }else {
            this.$message({
              message: '请输入用户名和密码',
              type: 'warning'
            });
          }
          return false;
        })
    }
// request拦截器
// 可以在请求发送之前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(
  config => {
// 可以在这里添加认证 token
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    // config.headers['Authorization'] = 'Bearer your-token';
    config.headers['token'] = localStorage.getItem("token");
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

  4. 后端设置jwt拦截器,并配置

/**
 * @Author: EstellaQ
 * @Date: 2025/4/7 9:20
 * @Description: jwt拦截器
 **/
public class JwtInterceptor implements HandlerInterceptor {

    @Resource
    private UserMapper userMapper;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        if (StrUtil.isBlank(token)) {
            token = request.getParameter("token");
        }
        //如果不是映射到方法直接通过
        if (handler instanceof HandlerMethod) {
            //通过反射拿到方法上的注解
            AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
            if (annotation != null) {
                return true;
            }
        }
        //执行认证
        if (StrUtil.isBlank(token)) {
            throw new ServiceException(401, "请登录");
        }
        //获取token中的userid
        String userId;
        try {
            //解码
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException e) {
            throw new ServiceException(401, "请登录");
        }
        //根据token中的userid查询数据库
        User user = userMapper.selectByUserName(userId);
        if (user == null) {
            throw new ServiceException(401, "请登录");
        }
        //用户密码加签验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token); //验证token
        } catch (JWTVerificationException e) {
            throw new ServiceException(401, "请登录");
        }
        return true;
    }
}
/**
 * @Author: EstellaQ
 * @Date: 2025/4/7 9:54
 * @Description: 配置拦截规则
 **/
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/**")   //拦截所有的请求路径
                .excludePathPatterns("/login"); //将登录放行

        super.addInterceptors(registry);
    }

    @Bean
    public JwtInterceptor jwtInterceptor() {
        return new JwtInterceptor();
    }
}

  5. 前端设置接口接收之后的拦截器,若权限认证失败,返回401,则返回登录接口

request.interceptors.response.use(
  response => {
// 处理响应数据
    let res = response.data
    // 兼容服务端返回的字符串数据
    if (typeof res == 'string') {
      res = res ? JSON.parse(res) : res
    }
    if (res.code === 401) {
      router.push("/login")
    }
    return res
  },
  error => {
// 处理响应错误
    return Promise.reject(error);
  }
);

相关文章:

  • 如何更好的理解 beforeEach 全局前置守卫,在处理路由跳转前触发,怎么实现常用的全局权限校验、登录状态检查的呢?
  • 深入解析SQL多表查询:核心技巧与实战示例
  • 【前端进阶】可选链与空值合并:接口数据容错处理的最佳实践
  • G-升!龙!_牛客周赛 Round 88
  • 深入源码级别看spring bean创建过程
  • Go语言类型捕获及内存大小判断
  • JVM核心机制:类加载×字节码引擎×垃圾回收机制
  • 硬盘分区格式方案之 MBR(Master Boot Record)主引导记录详解 笔记250407
  • 七彩虹隐星G15笔记本信息
  • 优化 Django 数据库查询
  • 数据库——Mysql
  • Vue学习笔记 - 安装与环境搭建
  • AI浪潮下的IT职业转型:医药流通行业传统IT顾问的深度思考
  • Java面试黄金宝典40
  • 小甲鱼python【p3】
  • Vue.js 实现下载模板和导入模板、数据比对功能核心实现。
  • Scala-面向对象2和集合
  • 解决 Kubernetes 中容器 `CrashLoopBackOff` 问题的实战经验
  • SpringBoot底层-数据源自动配置类
  • 版本控制工具——SVN
  • 音乐节困于流量
  • 消息人士称泽连斯基已启程前往土耳其
  • 小耳朵等来了春天:公益义诊筛查专家走进安徽安庆
  • 从《让·桑特伊》到《追忆》,假故事的胜利
  • 杭勇已任常州市政协党组成员,此前任常州市委常委、秘书长
  • 4月份全国企业销售收入同比增长4.3%