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

Javaweb登录校验

登录校验

JWT令牌的相关操作需要添加相关依赖

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

一、摘要

场景:当我们想要访问一个网站时,我们一般都需要进行登录验证,这时候就会涉及到一系列的问题

问题:

  • 什么时候进行登录校验?
  • 登录校验你该如何实现?如何设计高效,高健壮性的校验方式?
  • 进行登录校验时,你是以什么方式进行数据传递的?如何实现数据的传递

二、为什么要进行身份校验

试想以下场景,我们在如果我们对一个网站不进行有效的登录校验,而是可以直接通过网址:http://localhost:90/#/system/emp直接进入到网站内部,是不是极其不安全,我们应该在响应每一次请求前都进行一次登录校验,如果用户还没有登录。那么就必须先进行登录校验才能进行后续操作

在这里插入图片描述

三、拦截器

我们已经知道使用登录校验的使用场景,那么我们该如何设计一个高效的登录校验功能?是在每一个请求处理函数里面都添加一次if判断吗?这显然是不合理的,如果我们一个网站功能很复杂,那么面对如此多的请求并在每一个请求中都添加一个if判断就显得十分low,而且健壮性不高,不利于维护。因此,我们就引出了拦截器的概念,我们创建一个工具类,用于处理每一次请求,我们每次向服务器发送请求时,都需要先经过拦截器,经过身份校验后再能传递到对应的处理函数,然后,服务器响应回来的数据同样需要先经过拦截器才能返回给浏览器

在这里插入图片描述

四、传递数据三种方式

我们已经知道拦截器的概念了,接下来就很有必要了解数据传递这样玩意,由于HTTP 协议是无状态的,这意味着每个请求都是独立的,服务器不会保存关于之前请求的任何信息。每次客户端发送请求时,服务器都会独立处理该请求,并在发送响应后忘记关于该请求的任何信息。这就意味着,即使我们已经通过登录页面登录进去了,但是浏览器还是不知道我们已经登录了,因为每一次请求都是独立的,所以后续我们进行的每一次请求,都至少要携带用户登录的信息,如用户名,密码等,这样才能正常通过拦截器,将数据发送给后端继续后续操作,如果不能实现数据传递,这样就很麻烦了,所以这里就引出了以下几种数据传递的方式,会话跟踪技术

在这里插入图片描述

  • 客户端会话跟踪技术:Cookie
  • 服务器会话跟踪技术:Session
  • 令牌技术

这三种方式各有优缺点,以下是三种技术的优缺点对比

在这里插入图片描述

简单解释为什么 session会话无法在集群中使用:

在我们进行登录验证时,如果用户没有进行登录过,就会在服务器那边创建一个session记录,在用户下次登录时会自动检测判断用户有没有登录过,但是集群技术呢,会将我们的数据存储在不同的服务器中,而不是只保存在一个服务器,这就导致了如果我们下次访问资源时访问了另一个没有进行登录校验过的服务器,就得重新进行验证,所以无法在集群中有效使用

由于session的底层还是由cookie,所以无法在移动端中使用,而且用户甚至可以禁用掉cookie,慢慢的,cookie和session技术已不再是主流,目前的主流技术就是令牌技术,这里我们以JWT令牌技术为例

在这里插入图片描述

为什么令牌技术能够解决集群认证,移动端认证等问题?

在我们们的登录请求发送到后端时,后端服务器会检测有没有创建令牌,如果没有,那么就创建令牌并传递回前端,然后前端将令牌保存起来,注意这里的保存可以保存在任意存储空间中,可以保存到cookie,也可以保存在其他地方,在后续的请求中,前端浏览器会自动将令牌发送给后端,这样就解决了cookie技术不能在安卓中使用的问题,同时,因为令牌经Base64编码和数字签名加密,安全性也不需要考虑,解决了cookie安全性不高的问题,由于令牌也不在后端服务器中保存,因此也不会存在集群的问题。在令牌发送给后端后会解析令牌,获取其中的数据,这样就能通过登录校验了。

五、相关会话技术的实现

1、cookie技术
@Slf4j
@RestController
public class SessionController {/*** 设置Cookie* @param response 响应* @return 设置Cookie*/@GetMapping("/setCookie")public Result setCookie(HttpServletResponse response){response.addCookie(new Cookie("name", "zhangsan"));log.info("设置Cookie成功, name=zhangsan");return Result.success();}/*** 获取Cookie* @param request 请求* @return 获取Cookie*/@GetMapping("/getCookie")public Result getCookie(HttpServletRequest request){Cookie[] cookies = request.getCookies();for(Cookie cookit : cookies){if(cookit.getName().equals("name")){log.info("获取Cookie成功, name={}", cookit.getValue());}}return Result.success();}}
2、session技术

如果是第一次请求,那么session对象是不存在的,后端服务器会自动创建一个session对象,每个对象都有一个对应的ID,然后服务器响应数据时,会以cookie的方式将sessionID返回给浏览器,即在响应头中添加了一个Set-Cookie:JSESSIONID=session_ID,然后浏览器会自动将这个cookie存储在浏览器,然后在后续的每一次请求当中都会将cookie中的数据获取出来并携带到服务端,然后服务器通过请求中的session_ID查看本地有没有这个会话对象,这样就能在同一个会话的多次请求中共享数据了

   /*** 设置Session* @param session 会话* @return 设置Session*/@GetMapping("/session1")// 如果session对象不存在,会自动创建一个,如果存在,会直接返回session对象public Result session1(HttpSession session){log.info("HttpSession-s1: {}", session.hashCode());session.setAttribute("loginUser", "tom"); //往session中存储数据log.info("session.getAttribute: {}", session.getAttribute("loginUser"));return Result.success();}/*** 设置Session* @param request 请求* @return 设置Session*/@GetMapping("/session2")public Result session2(HttpServletRequest request){// 如果session对象不存在,会自动创建一个,如果存在,会直接返回session对象HttpSession session = request.getSession();log.info("HttpSession-s2: {}", session.hashCode());Object loginUser = session.getAttribute("loginUser"); //从session中获取数据log.info("loginUser: {}", loginUser);return Result.success(loginUser);}
3、JWT令牌

同样的,第一次请求时没有JWT令牌会创建令牌并返回给前端,前端会将这个令牌保存起来,在以后的每一次请求中,都会在请求头中携带这个令牌(token),然后通过后端拦截器或过滤器的解析验证,进行后续操作

 /*** 生成JWT令牌*/@Testpublic void generateJwt() {String signKey = "terminal";Long expire = 43200000L;Map<String, Object> claims = new HashMap<>();claims.put("username", "admin");String jwt = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();System.out.println("jwt = " + jwt);}/*** 解析JWT令牌*/@Testpublic void parseJWT() {String signKey = "terminal";String token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzE3MDQxMjk2fQ.p-UYxhJQY30cYELv8hETYHWMs74D-lo1a0tdi3xXXBU";String jwt = Jwts.parser().setSigningKey(signKey).parseClaimsJws(token).getBody().toString();System.out.println("jwt = " + jwt);}

六、使用过滤器和拦截器进行身份验证

1、过滤器(Filter)
package com.example.filter;import com.alibaba.fastjson.JSONObject;
import com.example.pojo.Result;
import com.example.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
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;// @WebFilter(urlPatterns = "/*") 表示拦截所有请求
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("demoFilter init");Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// 获取URLString url = request.getRequestURI().toString();if (url.contains("login")) {filterChain.doFilter(servletRequest, servletResponse);return;}// 获取tokenString jwt = request.getHeader("token");log.info("token = {}", jwt);// 如果token为空,但会未登录信号if (!StringUtils.hasLength(jwt)) {Result result = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(result);response.getWriter().write(notLogin);return;}try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("jwt令牌无效");Result result = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(result);response.getWriter().write(notLogin);return;}//放行filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {log.info("demoFilter destroy");Filter.super.destroy();}
}
2、拦截器(Interceptor)
  • 拦截器配置
package com.example.config;import com.example.interceptor.LoginCheckInterceptor;
import lombok.extern.slf4j.Slf4j;
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 设置该类为一个配置类
@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册一个拦截器,拦截除了/login之外的所有请求registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");}
}
  • 拦截器处理逻辑
package com.example.interceptor;import com.alibaba.fastjson.JSONObject;
import com.example.pojo.Result;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 拦截器处理逻辑*/
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override// 目标资源方法前执行,true为方行,false为拦截// 与doFilter的fileChain前执行的方法类似public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取tokenString token = request.getHeader("token");// 如果token为空,返回未登录信号if(!StringUtils.hasLength(token)){Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);response.getWriter().write(notLogin);return false;}// 放行return true;}@Override// 目标资源方法后执行后执行// 与doFilter的fileChain后执行的方法类似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("afterCompletion");}
}

相关文章:

Javaweb登录校验

登录校验 JWT令牌的相关操作需要添加相关依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>一、摘要 场景&#xff1a;当我们想要访问一个网站时&am…...

vxe-table 列表过滤踩坑_vxe-table筛选

但是这个过滤输入值必须是跟列表的值必须一致才能查到&#xff0c;没做到模糊查询的功能&#xff0c;根据关键字来过滤并没有实现。 下面提供一下具体实现方法&#xff1a;&#xff08;关键字来过滤&#xff09; filterNameMethod({ option, row }) {if (row.name.indexOf(op…...

计算机网络:网络层 - IP数据报的转发

计算机网络&#xff1a;网络层 - IP数据报的转发 基于终点转发最长前缀匹配二叉线索树路由表特殊路由特定主机路由默认路由 IP多播 基于终点转发 路由器转发报文时&#xff0c;是通过报文中的目的地址字段来转发的&#xff0c;也即是说路由器只知道终点的IP地址&#xff0c;根…...

颠覆与创新:探寻Facebook未来的发展路径

Facebook&#xff0c;这个曾经引领社交网络革命的巨头&#xff0c;在如今竞争激烈的科技市场中&#xff0c;正面临着前所未有的挑战和机遇。如何在不断变化的数字世界中保持竞争力&#xff0c;成为业界领先者&#xff0c;这是摆在Facebook面前的重要课题。本文将探寻Facebook未…...

太湖远大毛利率下滑:研发费用率远低同行,募投项目合理性疑点重重

《港湾商业观察》黄懿 6月20日&#xff0c;浙江太湖远大新材料股份有限公司&#xff08;以下简称“太湖远大”&#xff0c;873743.NQ&#xff09;即将迎来过会。 2023年11月30日&#xff0c;太湖远大所提交的上市申请材料正式获北交所受理&#xff0c;保荐机构为招商证券&…...

赶紧收藏!2024 年最常见 20道设计模式面试题(八)

上一篇地址&#xff1a;赶紧收藏&#xff01;2024 年最常见 20道设计模式面试题&#xff08;七&#xff09;-CSDN博客 十五、模板方法模式是如何在父类中定义算法框架的&#xff1f; 模板方法模式通过在父类&#xff08;通常是一个抽象类&#xff09;中定义算法的骨架&#x…...

JAVA学习-练习试用Java实现“比较版本号”

问题&#xff1a; 给定两个版本号 version1 和 version2 &#xff0c;请比较它们。 版本号由一个或多个修订号组成&#xff0c;各修订号由一个 . 连接。每个修订号由 多位数字 组成&#xff0c;可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号&#xff0c;…...

云原生分级SLA

云原生分级SLA&#xff08;Service Level Agreement&#xff0c;服务等级协议&#xff09;规则是为了确保云服务提供商和客户之间对服务性能、可用性和其他关键指标有明确的理解和期望。这些规则通常基于业务需求和技术实现来制定&#xff0c;并根据服务的不同级别进行分级。以…...

java干货 线程间通信

文章目录 一、线程间通信1.1 为什么要处理线程间通信&#xff1f;1.2 什么是等待唤醒机制&#xff1f; 二、等待唤醒机制使用2.1 等待唤醒机制用到的方法2.1.1 wait2.1.2 notify 2.2 线程通信代码实践2.2.1 重要说明2.2.2 代码 一、线程间通信 1.1 为什么要处理线程间通信&…...

【人机交互 复习】第6章 交互式系统的设计

一、设计框架 1.在建立了一组需求之后&#xff0c;设计即将开始&#xff0c;建议采取自上面下的方式&#xff0c;首先把重点放在大的方面&#xff0c;生成低保真且不包含具体细节的方案&#xff0c;一般通过写剧本来确定交互设计模式与逻辑。 2.设计框架&#xff1a; 先站在一个…...

1-函数极限与连续

1 2 平方项没有考虑到&#xff08;其正负&#xff09;...

【C++题解】1670 - 象棋大赛

问题&#xff1a;1670 - 象棋大赛 类型&#xff1a;分支问题 题目描述&#xff1a; 市里要组织象棋大赛&#xff0c;年龄在 8∼30 周岁之间的选手可以报名参赛。为了公平起见&#xff0c;大赛组委会将选手们分了青年组、少年组和儿童组&#xff0c;大赛组委会规定&#xff1a…...

Samba:用于高效无限上下文语言建模的简单混合状态空间模型

Samba: Simple Hybrid State Space Models for Efficient Unlimited Context Language Modeling &#x1f4dc; 文献卡 Samba: Simple Hybrid State Space Models for Efficient Unlimited Context Language Modeling作者: Liliang Ren; Yang Liu; Yadong Lu; Yelong Shen; …...

通俗易懂的ChatGPT原理简介

一、引言 随着人工智能的发展&#xff0c;聊天机器人已经成为我们生活中的常见工具。而在众多聊天机器人中&#xff0c;ChatGPT 无疑是最受关注的一个。ChatGPT 是由 OpenAI 开发的一种基于生成式预训练模型&#xff08;GPT&#xff09;的大型语言模型。本文将通俗易懂地介绍 …...

你认为 AI 作图程序「MidJourney」有哪些比较好用的关键词?

玩了一段时间的MidJourney&#xff0c;打算把这个回答做成资源帖。也欢迎在评论区补充讨论。 MidJourney的极简指南 快速上手 装discord&#xff0c;或者直接打开网址 https://discord.gg/midjourney 注册用户。进入Midjourney的官方服务器后&#xff0c;在左侧栏找一个newb…...

9.2JavaEE——JDBCTemplate的常用方法(一)excute()方法

execute()方法用于执行SQL语句&#xff0c;其语法格式如下&#xff1a; jdTemplate.execute("SQL 语句");下面以创建数据表的SQL语句为例&#xff0c;来演示excute()方法的使用&#xff0c;具体步骤如下。 1、创建数据库 在MySQL中&#xff0c;创建一个名为spring的…...

正向代理和反向代理的区别

正向代理和反向代理的主要区别在于代理服务器所服务的对象不同。 正向代理&#xff08;Forward Proxy&#xff09;&#xff1a;正向代理的客户端是内部网络的用户。当内部网络的用户想要访问外部网络&#xff08;例如互联网&#xff09;时&#xff0c;可以通过正向代理服务器来…...

express入门03增删改查

目录 1 搭建服务器2 静态文件托管3 引入bootstrap4 引入jquery5 编写后端接口5.1 添加列表查询方法5.2 添加路由5.3 添加数据表格 总结 我们前两篇介绍了如何利用express搭建服务器&#xff0c;如何实现静态资源托管。那利用这两篇的知识点&#xff0c;我们就可以实现一个小功能…...

【usb设备端口异常】——使用ls /dev/video*查看设备号时出现报错:ls:无法访问‘/dev/video*‘: 没有那个文件或目录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ls:无法访问/dev/video*: 没有那个文件或目录1. 问题描述2. 原因分析3. 解决方法 总结 前言 一、ls:无法访问’/dev/video*: 没有那个文件或目录 使用的这…...

Java实现异步开发的方式

1&#xff09;、继承 Thread 2&#xff09;、实现 Runnable 接口 3&#xff09;、实现 Callable 接口 FutureTask &#xff08;可以拿到返回结果&#xff0c;可以处理异常&#xff09; 4&#xff09;、使用线程池 区别&#xff1a;1、2&#xff09;不能得到返回值 …...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

mac:大模型系列测试

0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何&#xff0c;是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试&#xff0c;是可以跑通文章里面的代码。训练速度也是很快的。 注意…...