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令牌
     */
    @Test
    public 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令牌
     */
    @Test
    public 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 {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("demoFilter init");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 获取URL
        String url = request.getRequestURI().toString();
        if (url.contains("login")) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        // 获取token
        String 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);
    }

    @Override
    public 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 {
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public 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 {
        // 获取token
        String 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");
    }
}

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

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

相关文章

真空玻璃可见光透射比检测 玻璃制品检测 玻璃器皿检测

建筑玻璃检测 防火玻璃、钢化玻璃、夹层玻璃、均质钢化玻璃、平板玻璃、中空玻璃、真空玻璃、镀膜玻璃夹丝玻璃、光栅玻璃、压花玻璃、建筑用U形玻璃、镶嵌玻璃、玻璃幕墙等 工业玻璃检测 钢化安全玻璃、电加温玻璃、玻璃、半钢化玻璃、视镜玻璃、汽车安全玻璃、汽车后窗电热…

Docker+MySQL:打造安全高效的远程数据库访问

在现代应用开发和部署中&#xff0c;数据库是关键组件之一。无论是开发环境还是生产环境&#xff0c;快速、可靠地部署和管理数据库都是开发人员和运维人员面临的常见挑战之一。 Docker是一种流行的容器化技术&#xff0c;它使得应用程序的部署和管理变得非常简单和高效。通过使…

大数据-数据分析初步学习,待补充

参考视频&#xff1a;数据分析只需3小时从入门到进阶&#xff08;up亲身实践&#xff09;_哔哩哔哩_bilibili 数据指标&#xff1a; 对当前业务有参考价值的统计数据 分类&#xff1a;用户数据&#xff0c;业务数据&#xff0c;行为数据 用户数据 存量&#xff1a; DAU&#…

CSS3中鲜为人知但非常强大的 Clip-Path 属性

CSS3中鲜为人知但非常强大的 Clip-Path 属性 在CSS3中,clip-path属性可以让我们快速创建各种各样的不规则图形,而无需使用图片或者复杂的绘图工具。它可以帮助我们实现一些非常出色的视觉效果,但遗憾的是它并不是很常见。 clip-path属性可以接受多种不同的值,比如polygon()、…

Matlab终于能够实现Transformer预测了

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 数据介绍 结果展示 完整代码 今天…

Day9—Spark运行模式及RDD的创建

Spark概述 大数据开发的总体架构 可以看到&#xff0c;在数据计算层&#xff0c;作为Hadoop核心组成的MapReduce可以结合Hive通过类SQL的方式进行数据的离线计算&#xff08;当然也可以编写独立的MapReduce应用程序进行计算&#xff09;&#xff1b;而Spark既可以做离线计算&a…

金属配件加工厂设备远程监控

随着科技的飞速发展&#xff0c;智能制造已成为制造业转型升级的重要方向。在金属配件加工领域&#xff0c;设备的稳定运行和高效管理对于提升产品质量、降低生产成本至关重要。HiWoo Cloud平台凭借其强大的远程监控功能&#xff0c;为金属配件加工厂提供了全新的解决方案&…

RabbitMQ详解-06RabbitMQ高级

1. 过期时间TTL 可以对消息设置预期的时间&#xff0c;在这个时间内都可以被消费者接收获取&#xff1b;过了之后消息自动被删除。RabbitMQ可以对消息和队列设置TTL。有以下两种设置方法&#xff1a; 通过队列属性设置&#xff0c;队列中所有消息都有相同的过期时间。对消息进…

省市区下拉选择:3个el-select(附完整代码+json)

目录 直接上做出的效果&#xff1a; 页面代码&#xff1a; 使用click.native&#xff1a; data及引入&#xff1a; 初始化&#xff1a; methods&#xff1a; JSON: 示例结构&#xff1a; 1.code.json 2.pca-code.json 回显&#xff1a; 视频效果&#xff1a; 直接上做出…

5个好用的中文AI大语言模型_中文大语言模型

AI大语言模型&#xff08;Large Language Models, LLMs&#xff09;是近1-2年来人工智能领域的重要发展&#xff0c;它们通过深度学习技术&#xff0c;特别是基于Transformer的架构&#xff08;如GPT、BERT等&#xff09;&#xff0c;实现了对自然语言处理的巨大突破。 AI大语…

Vulkan入门系列2- 绘制三角形

概述&#xff1a; Vulkan的学习曲线是比较陡峭的&#xff0c;学习Vulkan刚开始像是在爬一个陡坡&#xff0c;等上了这个陡坡之后&#xff0c;后面学习曲线就相对比较平缓了。那么在Vulkan中绘制一个三角形&#xff0c;就相当于是在爬这样一个陡坡&#xff0c;因为绘制三角形需…

「51媒体」时尚类媒体邀约宣发资源

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 时尚类媒体邀约宣发资源可以多样化且针对性地满足品牌或活动的推广需求。以下是一些主要的资源及其特点&#xff1a; 时尚杂志&#xff1a;国内外知名时尚杂志&#xff0c;如《Vogue》、…

SparkSQL的分布式执行引擎-Thrift服务:学习总结(第七天)

系列文章目录 SparkSQL的分布式执行引擎 1、启动Thrift服务 2、beeline连接Thrift服务 3、开发工具连接Thrift服务 4、控制台编写SQL代码 文章目录 系列文章目录前言一、SparkSQL的分布式执行引擎(了解)1、启动Thrift服务2、beeline连接Thrift服务3、开发工具连接Thrift服务4、…

MS3121地隔离放大器

MS3121 是一款应用于车载音频系统的地隔离放大 器。芯片可以很好地解决汽车音频系统中的绕线电阻问 题&#xff0c;以及由车载电子设备带来的噪声问题。另外&#xff0c;芯片 所需要的外围电容小&#xff0c;便于系统的集成。注意&#xff0c;芯片的 地电位需要和后级音频功…

Flutter第十四弹 抽屉菜单效果

目标&#xff1a; 1.怎么构建抽屉菜单效果&#xff1f; 2.抽屉菜单怎么定制&#xff1f; 一、抽屉菜单 侧滑抽屉菜单效果 1.1 抽屉菜单入口 Flutter 的脚手架Scaffold&#xff0c;默认提供了抽屉菜单效果入口。 主页面采用一个简单的页面&#xff0c;侧滑菜单首先使用一个I…

ARP地址解析协议详解:

ARP&#xff1a;地址解析协议 – 以下3种ARP正常均只能在同一个广播域内使用 AARP 正向ARP 已知对端IP地址&#xff0c;通过广播来获取对端的MAC地址 RARP 反向ARP 已知对端的MAC地址&#xff0c;通过二层单播、三层广播来获取对端的IP地址 FARP 无故ARP 在设备刚获取…

电商API接口详述:涵盖订单、库存等多功能接口介绍

电商商家自研管理系统&#xff0c;线下ERP系统或WMS系统想要接入电商平台订单打单发货&#xff0c;通过点三电商API可以一键对接多个电商平台&#xff0c;帮助商家、ERP/WMS服务商快速开发电商模块&#xff0c;实现电商业务管理功能&#xff0c;那么点三电商API接口有哪些可用接…

HTTP 抓包工具——Fiddler项目实战

网络爬虫实质上是模拟浏览器向 Web 服务器发送请求。对于一些简单的网络请求&#xff0c;我们 可以通过查看 URL 地址来构造请求&#xff0c;但对于一些稍复杂的网络请求&#xff0c;仍然通过观察 URL 地 址将无法构造正确。因此我们需要对这些复杂的网络请求进行捕获分…

一文带你理清同源和跨域

1、概述 前后端数据交互经常会碰到请求跨域&#xff0c;什么是跨域&#xff0c;为什么需要跨域&#xff0c;以及常用有哪几种跨域方式&#xff0c;这是本文要探讨的内容。 同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。同源策略限制了从同一个源加载的…

协同编辑:只是在线协作这么简单吗?揭秘协同编辑的深层价值

经常很多朋友咨询&#xff0c;无忧企业文档是否支持协同编辑&#xff0c;首先肯定是支持的。但是&#xff0c;我发现很多人对于“协同编辑”的理解可能比较表面&#xff0c;仅仅停留在多人同时编辑一份文档的层面。实际上&#xff0c;协同编辑的功能远不止于此&#xff0c;它更…