基于Token认证的登录功能实现

news2024/11/20 11:30:11

  • Session 认证和 Token 认证
  • 过滤器和拦截器

上篇文章我们讲到了过滤器和拦截器理论知识以及 SpringBoot 集成过滤器和拦截器,本篇文章我们使用过滤器和拦截器去实现基于 Token 认证的登录功能。

一、登录校验 Filter 实现

1.1、Filter 校验流程图

  • 获得请求 url
  • 判断请求 url 中是否包含 login ,如果包含,说明是登录操作,放行。
  • 获取请求头中的令牌(Token
  • 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
  • 解析 token ,如果解析失败,返回错误结果(未登录)。
  • 放行
1.2、Filter 校验实现

新建一个 SpringBoot 项目 loginFilter,引入之前文章提到的 JWT 工具类。

JWTUtils代码如下:

package com.duan.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;

/**
 * @author db
 * @version 1.0
 * @description JWTUtils
 * @since 2023/12/31
 */
public class JWTUtils {

    // 密钥
    private static String signKey = "cxykk1217";
    // 过期时间
    private static Long expire = 1000L*60*30; // 30分钟

    /**
     * 生成JWT
     * @param claims JWT第二部分负载payload中存储的内容
     * @return
     */
    public static String generateJwt(Map<String,Object> claims){
        String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, signKey)
                .addClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();

        return jwt;
    }

    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser().setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}

新建 LoginFilter 类并实现 Filter ,在 doFilter 方法中进行登录校验。代码如下:

package com.duan.filter;

import com.alibaba.fastjson.JSONObject;
import com.duan.pojo.Result;
import com.duan.utils.JWTUtils;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description LoginFilter
 * @since 2024/1/11
 */
@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        // 1. 获得请求路径
        String url = httpServletRequest.getRequestURL().toString();

        // 2. 判断请求的资源路径
        if(url.contains("/login")){
            // 登录功能,放行
            chain.doFilter(request,response);
            return;
        }

        // 3. 获取请求头token
        String token = httpServletRequest.getHeader("token");
        if(token == null){
            // 返回登录页面
            Result noLogin = Result.error("NO_LOGIN");
            // 使用原始方式给客户端响应数据
            // 把noLogin 对象转成json字符串返回
            String jsonString = JSONObject.toJSONString(noLogin);
            httpServletResponse.getWriter().write(jsonString);
            return;
        }
        // 4. 解析token
        try{
            JWTUtils.parseJWT(token);
        }catch (Exception e){
            // token存在问题
            // 返回登录页面
            Result noLogin = Result.error("NO_LOGIN");
            // 使用原始方式给客户端响应数据
            // 把noLogin 对象转成json字符串返回
            String jsonString = JSONObject.toJSONString(noLogin);
            httpServletResponse.getWriter().write(jsonString);
            return;
        }
        // 5. token解析成功,放行
        chain.doFilter(request,response);
    }
}

注意:使用 @WebFilter 配置过滤器时,启动类上一定要使用 @ServletComponentScan 注解。

启动程序,通过 postman 来访问 login 和 getUser 方法。


代码地址:https://gitee.com/duan138/practice-code/tree/dev/loginFilter

二、登录校验拦截器实现

2.1、Interceptor 校验流程图

  • 获得请求 url
  • 判断请求 url 中是否包含 login ,如果包含,说明是登录操作,放行。
  • 获取请求头中的令牌(Token
  • 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
  • 解析 token ,如果解析失败,返回错误结果(未登录)。
  • 放行

通过流程图可以看出,过滤器和拦截器实现的流程是一样的,只不过实现方式不一样。

2.2、Interceptor 校验

新建一个 SpringBoot 项目 loginInterceptor,引入之前文章提到的 JWT 工具类。

JWTUtils 代码如下:

package com.duan.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;

/**
 * @author db
 * @version 1.0
 * @description JWTUtils
 * @since 2023/12/31
 */
public class JWTUtils {

    // 密钥
    private static String signKey = "cxykk1217";
    // 过期时间
    private static Long expire = 1000L*60*30; // 30分钟

    /**
     * 生成JWT
     * @param claims JWT第二部分负载payload中存储的内容
     * @return
     */
    public static String generateJwt(Map<String,Object> claims){
        String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, signKey)
                .addClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();

        return jwt;
    }

    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser().setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}

新建 LoginInterceptor 类并实现 HandlerInterceptor,在 preHandle 方法中进行登录校验。代码如下:


package com.duan.handler;

import com.alibaba.fastjson.JSONObject;
import com.duan.pojo.Result;
import com.duan.utils.JWTUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description LoginInterceptor
 * @since 2023/12/20
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {

    // 目标方法执行前调用  true:放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        // 1. 获得请求路径
        String url = request.getRequestURL().toString();

        // 2. 判断请求的资源路径
        if(url.contains("/login")){
            // 登录功能,放行
            return true;
        }

        // 3. 获取请求头token
        String token = request.getHeader("token");
        if(token == null){
            // 返回登录页面
            Result noLogin = Result.error("NO_LOGIN");
            // 使用原始方式给客户端响应数据
            // 把noLogin 对象转成json字符串返回
            String jsonString = JSONObject.toJSONString(noLogin);
            response.getWriter().write(jsonString);
            return false;
        }
        // 4. 解析token
        try{
            JWTUtils.parseJWT(token);
        }catch (Exception e){
            // token存在问题
            // 返回登录页面
            Result noLogin = Result.error("NO_LOGIN");
            // 使用原始方式给客户端响应数据
            // 把noLogin 对象转成json字符串返回
            String jsonString = JSONObject.toJSONString(noLogin);
            response.getWriter().write(jsonString);
            return false;
        }
        // 5. token解析成功,放行
        return true;
    }

    // 目标方法执行后调用
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    // 请求处理后调用
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Completion...");
    }
}

在 config 包中 LoginInterceptorConfig 方法配置新建的 loginInterceptor。


package com.duan.config;

import com.duan.handler.LoginInterceptor;
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;

/**
 * @author db
 * @version 1.0
 * @description LoginInterceptorConfig  注册拦截器
 * @since 2023/12/20
 */
@Configuration
public class LoginInterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**");

    }
}

启动程序,通过 postman 来访问 login 和 getUser 方法。

代码地址:https://gitee.com/duan138/practice-code/tree/dev/loginInterceptor

三、总结

通过过滤器和拦截器实现基于 Token 的登录功能,加深了对过滤器和拦截器的理解,同时也梳理了基于 Token 认证登录的流程,在现在项目中常用的是基于 SpringSecurity + JWT 登录认证方式,后续我们来看一看基于 Spring security + JWT 怎么去实现登录控制。


参考

1.https://space.bilibili.com/1809189461


改变你能改变的,接受你不能改变的,关注公众号:程序员康康,一起成长,共同进步。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Express 应用生成器(脚手架)的安装与使用

1、简介 自动生成一个express搭建的项目结构 官网&#xff1a;Express 应用生成器 2&#xff0c;使用 2.1全局安装&#xff0c;使用管理员打开命令窗口 2.2、安装express # 全局安装express npm install -g express # 全局安装express脚手架 npm install -g express-gene…

BRC20通证的诞生与未来展望!如何导入bitget教程

BRC-20通证是什么&#xff1f; 嘿&#xff01;你知道BRC-20通证吗&#xff1f;这可是比特币区块链上的超级明星&#xff01;它们不依赖智能合约&#xff0c;而是把JSON代码刻在聪上&#xff0c;聪可是比特币的最小单位哦&#xff01;就像在比特币的乐高积木上盖房子&#xff0…

【量化交易故事】小明开启了量化创业之旅-01

故事开始于2023年的春天&#xff0c;小明是一位对金融市场充满热情的IT工程师。在经历了数次基于主观判断和个人情绪进行投资却收获平平后&#xff0c;他意识到传统交易方式中的人为因素难以避免&#xff0c;而这往往成为影响投资决策稳定性和准确性的关键障碍。在一次偶然的机…

bash shell基础命令

1.shell启动 shell提供了对Linux系统的交互式访问&#xff0c;通常在用户登录终端时启动。系统启动的shell程序取决于用户账户的配置。 /etc/passwd/文件包含了所有用户的基本信息配置&#xff0c; $ cat /etc/passwd root:x:0:0:root:/root:/bin/bash ...例如上述root账户信…

WorkPlus领先企业即时通信软件,提升团队沟通效率的利器

在企业工作中&#xff0c;高效沟通是推动团队协作和工作效率的关键。而企业即时通信软件成为了实现高效沟通的利器。作为一款领先的企业即时通信软件&#xff0c;WorkPlus以其卓越的性能和独特的功能&#xff0c;提升团队沟通效率&#xff0c;助力企业实现高效协作。 为什么选择…

Netty-Netty实现自己的通信框架

通信框架功能设计 功能描述 通信框架承载了业务内部各模块之间的消息交互和服务调用&#xff0c;它的主要功能如下&#xff1a; 基于 Netty 的 NIO 通信框架&#xff0c;提供高性能的异步通信能力&#xff1b; 提供消息的编解码框架&#xff0c;可以实现 POJO 的序列化和反…

QT上位机开发(usb设备访问)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 利用usb接口访问底层下位机&#xff0c;这是一种很常见的方式。目前比较简单的做法有两种&#xff0c;一种是usb转串口&#xff0c;另外一种是利用…

【期末考试】数据库综合复习宝典

目录 第一章 数据库系统概述 第二章 关系代数 第四章 关系数据库理论 第五章 数据库设计 第六章 数据库管理系统 第八章 事务管理 第一章 数据库系统概述 1.1三级模式 ①外模式&#xff1a;它为特定的应用程序或用户群体提供了一个数据视图&#xff0c;这个视图是独立于…

Qt编译OpenCV

1.CMake下载安装 官网地址&#xff1a;CMake - Upgrade Your Software Build System &#xff08;1&#xff09;下载后双击安装 &#xff08;2&#xff09;进入安装界面&#xff0c;点击【Next】 &#xff08;3&#xff09;同意协议&#xff0c;点击【Next】 &#xff08;4&a…

illustrator脚本 018 自动角线-1

这是一个自动加角线的脚本,来源于网络。 运行方式,先选择对象再执行脚本,无对话框。脚本不在好坏,你觉得对你有用最重要。 脚本中部分可修改选项: //初始化自定义标线的长度,宽度,离岸,出血等参数,可自行修改 lw=0.1*2.834646; //标线宽度 0.1 mm od=3*2.834646; //…

嵌入式软件开发人员有必要学习系统移植的知识吗?【ppt获取见文末】

《从零开始学ARM》的配套视频说明 为了让粉丝更好的学习我的新书里面的知识&#xff0c; 一口君特地录制了配套学习视频&#xff0c; 《从0学ARM第一期》 《从0学ARM第一期》 视频已经免费发布在B站&#xff0c; 而书中除了ARM汇编、裸机开发等知识&#xff0c;还涉及到…

HuiYong.Online 私有化博客系统

HuiYong.Online 私有化博客系统 一站式支持MarkDown、Drawio、XMind 免费、简单、强大... 用思维导图、流程图、写文章、做笔记、记录生活;搭建自己 / 组织 / 公司的知识储备系统;这里就是你所寻找的。 链接 官网&#xff1a;https://huiyong.onlineGithub&#xff1a;http…

【Docker】centos中及自定义镜像,并且上传阿里云仓库可提供使用

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是平顶山大师&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《【Docker】centos中及自定义镜像&#xff0c;…

【DB】MySQL版本5.7和8的区别,以及升级的注意事项

文章目录 1、MySQL版本5.7和8的区别2、MySQL 5.7升级8 1、MySQL版本5.7和8的区别 在数据库管理系统中&#xff0c;MySQL是一个广泛使用、开源的解决方案。它提供了强大的功能&#xff0c;同时具有优秀的性能和可扩展性。 MySQL 5的发布于2005年&#xff0c;在MySQL数据库的发…

配置CentOS系统以支持静态HTTP服务

CentOS是一个流行的Linux发行版&#xff0c;广泛应用于服务器环境。要配置CentOS系统以支持静态HTTP服务&#xff0c;您可以按照以下步骤进行操作&#xff1a; 安装Web服务器软件&#xff1a;CentOS自带了Apache HTTP服务器软件&#xff0c;您可以使用以下命令安装它&#xff1…

17_网络编程

文章目录 网络数据传输的基本原理UDP发送端步骤接收端步骤DatagramSocketDatagramPacket举例版本1&#xff1a;发送端发送消息,接收端接收并打印版本2&#xff1a;创建一个NetworkUtils工具类优化版本1版本3&#xff1a;发送端接收端相互发送版本4&#xff1a;使用多线程 TCP客…

SOLID 原则

单一功能原则 单一功能原则&#xff08;Single responsibility principle&#xff09;规定每个类都应该有一个单一的功能&#xff0c;并且该功能应该由这个类完全封装起来。所有它的&#xff08;这个类的&#xff09;服务都应该严密的和该功能平行&#xff08;功能平行&#x…

【GitHub项目推荐--13 个 Python 学习资源】【转载】

近些年&#xff0c;人工智能应用铺天盖地。人脸识别、老照片复活、换脸等应用都得益于人工智能算法。 许多人工智能算法封装的框架基于 Python 语言&#xff0c;这也导致了 Python 的热度只增不减。 Python 简单易学&#xff0c;根据 2020 年 StackOverflow 开发者调查报告显…

Spring boot - Task Execution and Scheduling @Async

SpringBoot的任务执行器 Spring Boot通过auto-configuration机制自动创建了任务执行器Task Execution&#xff0c;因此在SpringBoot项目中&#xff0c;你不需要任何配置、也不需要自己创建Task Execution就可以直接使用它。 Spring Boot通过auto-configuration机制创建的任务…

学会这个技巧,制作电子杂志SOEASY

​电子杂志是一种非常流行的传播方式&#xff0c;它能够以更加生动、直观的方式展示你的品牌和产品。通过电子杂志&#xff0c;你可以将文字、图片、视频等多种元素有机地结合起来&#xff0c;创造出令人难忘的视觉效果。 如果你想制作一本电子杂志&#xff0c;但不知道从何入…