SpringBootWeb 登录认证(day12)

登录功能

基本信息

 请求参数
        参数格式:application/json
        请求数据样例:

响应数据
      参数格式:application/json
       响应数据样例:

@Slf4j
@RestController
public class LoginController {@Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){log.info("员工登录: {}", emp);Emp e = empService.login(emp);//登录失败, 返回错误信息return Result.error("用户名或密码错误");}}
@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpMapper empMapper;@Overridepublic Emp login(Emp emp) {return empMapper.getByUsernameAndPassword(emp);}
}
/*** 员工管理*/
@Mapper
public interface EmpMapper {/*** 根据用户名和密码查询员工* @param emp* @return*/@Select("select * from emp where username = #{username} and password = #{password}")Emp getByUsernameAndPassword(Emp emp);
}

登录校验(重点)

问题分析

在未登录情况下,我们也可以直接访问部门管理、员工管理等功能。

所谓登录校验,指的是我们在服务器端接收到浏览器发送过来的请求之后,首先我们要对请求进行校验。先要校验一下用户登录了没有,如果用户已经登录了,就直接执行对应的业务操作就可以了;如果用户没有登录,此时就不允许他执行相关的业务操作,直接给前端响应一个错误的结果,最终跳转到登录页面,要求他登录成功之后,再来访问对应的数据。

那应该怎么来实现登录校验的操作呢?具体的实现思路可以分为两部分:

  1. 在员工登录成功后,需要将用户登录成功的信息存起来,记录用户已经登录成功的 标记
  2. 在浏览器发起请求时,需要在服务端进行 统一拦截,拦截后进行登录校验。

 会话技术

会话:用户打开浏览器,访问 web 服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含 多次 请求和响应。

会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。

会话跟踪方案:

  1. 客户端会话跟踪技术:Cookie
    数据存储在客户端浏览器当中
  2. 服务端会话跟踪技术:Session
    数据存储在服务端
  3. 令牌技术

会话跟踪方案对比

方案一 - Cookie

服务器端在给客户端在响应数据的时候,会自动的将 cookie 响应给浏览器,浏览器接收到响应回来的 cookie 之后,会自动的将 cookie 的值存储在浏览器本地。接下来在后续的每一次请求当中,都会将浏览器本地所存储的 cookie 自动地携带到服务端。


为什么这一切都是自动化进行的?
是因为 cookie 它是 HTTP 协议当中所支持的技术,而各大浏览器厂商都支持了这一标准。在 HTTP协议官方给我们提供了一个响应头和请求头:

响应头 Set-Cookie :设置Cookie数据的
请求头 Cookie:携带Cookie数据的

/*** Cookie、HttpSession演示*/
@Slf4j
@RestController
public class SessionController {//设置Cookie@GetMapping("/c1")public Result cookie1(HttpServletResponse response){response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookiereturn Result.success();}//获取Cookie@GetMapping("/c2")public Result cookie2(HttpServletRequest request){Cookie[] cookies = request.getCookies();for (Cookie cookie : cookies) {if(cookie.getName().equals("login_username")){System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie}}return Result.success();}
}
方案二 - Session



/*** Cookie、HttpSession演示*/
@Slf4j
@RestController
public class SessionController {@GetMapping("/s1")public Result session1(HttpSession session){log.info("HttpSession-s1: {}", session.hashCode());session.setAttribute("loginUser", "tom"); //往session中存储数据return Result.success();}@GetMapping("/s2")public Result session2(HttpServletRequest request){HttpSession session = request.getSession();log.info("HttpSession-s2: {}", session.hashCode());Object loginUser = session.getAttribute("loginUser"); //从session中获取数据log.info("loginUser: {}", loginUser);return Result.success(loginUser);}
}
方案三 - 令牌技术

JWT令牌

前面我们介绍了基于令牌技术来实现会话追踪。这里所提到的令牌就是用户身份的标识,其本质就是一个字符串。令牌的形式有很多,我们使用的是功能强大的 JWT 令牌。

介绍

全称:JSON  Web  Tokenhttps://jwt.io/

定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

组成:

第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

Base64:是一种基于64个可打印字符(A-Z a-z 0-9 + /)来表示二进制数据的编码方式。

JWT 令牌最典型的应用场景就是 登录认证

  • 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要 生成 一个 jwt 令牌,将生成的 jwt 令牌返回给前端。
  • 前端拿到 jwt 令牌之后,会将 jwt 令牌存储起来。在后续的每一次请求中都会将 jwt 令牌携带到服务端。
  • 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要 校验 一下令牌是否是有效。如果有效,就直接放行进行请求的处理。

JWT令牌的生成和校验


注意事项:

  1. JWT 校验时使用的签名秘钥,必须和生成 JWT 令牌时使用的秘钥是配套的。
  2. 如果 JWT 令牌解析校验时报错,则说明 JWT 令牌被篡改 或 失效了,令牌非法。
        <!--JWT令牌--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
//@SpringBootTest
class TliasWebManagementApplicationTests {@Testpublic void testUuid(){for (int i = 0; i < 1000; i++) {String uuid = UUID.randomUUID().toString();System.out.println(uuid);}}/*** 生成JWT*/@Testpublic void testGenJwt(){Map<String, Object> claims = new HashMap<>();claims.put("id",1);claims.put("name","tom");String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "itheima")//签名算法.setClaims(claims) //自定义内容(载荷).setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为1h.compact();System.out.println(jwt);}/*** 解析JWT*/@Testpublic void testParseJwt(){Claims claims = Jwts.parser().setSigningKey("itheima").parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY3MDQ2NDU0N30.yPLRyiusrlrmWeC4-dhInjFuAghPkmiHSRHd_DTKi9E").getBody();System.out.println(claims);}
}
令牌生成:登录成功后,生成JWT令牌,并返回给前端。
令牌校验:在请求到达服务端后,对令牌进行统一拦截、校验。

登录下发令牌

用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要 在请求头header中携带到服务端,请求头的名称为 token ,值为 登录时下发的 JWT令牌。 如果检测到用户未登录,则会返回如下固定错误信息:

令牌生成:

package com.itheima.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;public class JwtUtils {private static String signKey = "itheima";private static Long expire = 43200000L;/*** 生成JWT令牌* @param claims JWT第二部分负载 payload 中存储的内容* @return*/public static String generateJwt(Map<String, Object> claims){String jwt = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();return jwt;}/*** 解析JWT令牌* @param jwt JWT令牌* @return JWT第二部分负载 payload 中存储的内容*/public static Claims parseJWT(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();return claims;}
}
package com.itheima.controller;import com.itheima.pojo.Emp;
import com.itheima.pojo.Result;
import com.itheima.service.EmpService;
import com.itheima.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@Slf4j
@RestController
public class LoginController {@Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){log.info("员工登录: {}", emp);Emp e = empService.login(emp);//登录成功,生成令牌,下发令牌if (e != null){Map<String, Object> claims = new HashMap<>();claims.put("id", e.getId());claims.put("name", e.getName());claims.put("username", e.getUsername());String jwt = JwtUtils.generateJwt(claims); //jwt包含了当前登录的员工信息return Result.success(jwt);}//登录失败, 返回错误信息return Result.error("用户名或密码错误");}}

服务器响应的 JWT 令牌存储在本地浏览器哪里了呢?

  • 在当前案例中,JWT 令牌存储在浏览器的本地存储空间 local storage 中了。 local storage 是浏览器的本地存储,在移动端也是支持的。

我们在发起一个查询部门数据的请求,此时我们可以看到在请求头中包含一个 token(JWT令牌),后续的每一次请求当中,都会将这个令牌携带到服务端。

过滤器Filter

过滤器Filter介绍

  • 概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。
  • 过滤器可以把对资源的请求 拦截 下来,从而实现一些特殊的功能。
  • 过滤器一般完成一些 通用 的操作,比如:登录校验、统一编码处理、敏感字符处理等。

Filter 快速入门 步骤:

  1. 定义过滤器 :定义一个类,实现 Filter 接口,并重写其所有方法。
  2. 配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启 Servlet 组件支持。

Filter是是 JavaWeb 三大组件(Servlet、Filter、Listener)之一,并不是springboot提供的,故需要加上@ServletComponentScan 开启 Servlet 组件支持。

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;//@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {@Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Override //拦截到请求之后调用, 调用多次public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("Demo 拦截到了请求...放行前逻辑");//放行chain.doFilter(request,response);System.out.println("Demo 拦截到了请求...放行后逻辑");}@Override //销毁方法, 只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}
}
package com.itheima;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;@ServletComponentScan //开启了对servlet组件的支持
@SpringBootApplication
public class TliasWebManagementApplication {public static void main(String[] args) {SpringApplication.run(TliasWebManagementApplication.class, args);}}

详解(执行流程、拦截路径、过滤器链)

执行流程

拦截路径
过滤器链

介绍:一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链

顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。

小结

登录校验-Filter

登录校验Filter-流程

package com.itheima.filter;import com.alibaba.fastjson.JSONObject;
import com.itheima.pojo.Result;
import com.itheima.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;@Slf4j
//@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;//1.获取请求url。String url = req.getRequestURL().toString();log.info("请求的url: {}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。if(url.contains("login")){log.info("登录操作, 放行...");chain.doFilter(request,response);return;}//3.获取请求头中的令牌(token)。String jwt = req.getHeader("token");//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。if(!StringUtils.hasLength(jwt)){log.info("请求头token为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json --------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//5.解析token,如果解析失败,返回错误结果(未登录)。try {JwtUtils.parseJWT(jwt);} catch (Exception e) {//jwt解析失败e.printStackTrace();log.info("解析令牌失败, 返回未登录错误信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json --------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//6.放行。log.info("令牌合法, 放行");chain.doFilter(request, response);}
}
 <!--fastJSON--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency>

拦截器Interceptor

简介 & 快速入门

概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。

作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

Interceptor 快速入门 步骤:

  1. 定义拦截器,实现 HandlerInterceptor 接口,并重写其所有方法。
  2. 注册拦截器。

详解

拦截器-拦截路径
拦截器可以根据需求,配置不同的拦截路径:

拦截器-执行流程

登录校验- Interceptor

异常处理

程序开发过程中不可避免的会遇到异常现象

package com.itheima.exception;import com.itheima.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** 全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)//捕获所有异常public Result ex(Exception ex){ex.printStackTrace();return Result.error("对不起,操作失败,请联系管理员");}
}

上一节:

SpringBootWeb案例-2(day11)-CSDN博客

下一节:

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

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

相关文章

ASP.NET Core 实现微服务 - Consul 配置中心

这一次我们继续介绍微服务相关组件配置中心的使用方法。本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大&#xff0c;还是让我爱不起来。因为前面我们已经介绍了使用Consul 做为服务注册发现的组件 &#xff0c;那么干脆继续使用 Consul 来作为配置…

DeviceNet转Profinet网关如何革新污水处理行业!

DeviceNet转Profinet网关如何革新污水处理行业&#xff1f;在污水处理行业中&#xff0c;随着环保法规的日益严格和处理技术的不断进步&#xff0c;工业自动化技术的应用越来越广泛。特别是在提高生产效率、降低运营成本以及确保处理质量方面&#xff0c;自动化技术发挥着不可替…

(四)结合代码初步理解帧缓存(Frame Buffer)概念

帧缓存&#xff08;Framebuffer&#xff09;是图形渲染管线中的一个非常重要的概念&#xff0c;它用于存储渲染过程中产生的像素数据&#xff0c;并最终输出到显示器上。简单来说&#xff0c;帧缓存就是计算机图形中的“临时画布”&#xff0c;它储存渲染操作生成的图像数据&am…

58. Three.js案例-创建一个带有红蓝配置的半球光源的场景

58. Three.js案例-创建一个带有红蓝配置的半球光源的场景 实现效果 本案例展示了如何使用Three.js创建一个带有红蓝配置的半球光源的场景&#xff0c;并在其中添加一个旋转的球体。通过设置不同的光照参数&#xff0c;可以观察到球体表面材质的变化。 知识点 WebGLRenderer …

前端基础技术全解析:从HTML前端基础标签语言开始,逐步深入CSS样式修饰、JavaScript脚本控制、Ajax异步通信以及WebSocket持久通信

目录 前言&#xff1a; 1.前端技术html简单了解&#xff1a; 1.1HTML代码是由标签构成的。 1.2.HTML 文件基本结构 1.3.HTML 常见标签 标题标签: 段落标签: p 文本格式化标签 图片标签&#xff1a; 超链接标签: a 测试代码&#xff1a; 展示效果&#xff1a; 表单…

wireshark抓包工具新手使用教程

wireshark抓包工具新手入门使用教程 一、Wireshark软件安装二、Wireshark 抓包示范三、Wireshakr抓包界面四、Wireshark过滤器设置五、wireshark过滤器表达式的规则六、Wireshark抓包分析TCP三次握手七、Wireshark分析常用列标签格式 Wireshark是一款开源的网络协议分析工具&am…

中国省级产业结构高级化及合理化数据测算(2000-2023年)

一、数据介绍 数据名称&#xff1a;中国省级产业结构高级化、泰尔指数 数据年份&#xff1a;2000-2023年 数据范围&#xff1a;31个省份 数据来源&#xff1a;中国统计年鉴、国家统计局 数据整理&#xff1a;内含原始版本、线性插值版本、ARIMA填补版本 数据说明&#xf…

Qt 5.14.2 学习记录 —— 팔 QWidget 常用控件(3)

文章目录 1、cursor2、font3、toolTip4、focusPolicy5、styleSheeyt 1、cursor 改变鼠标光标形状。 在Qt Designer界面中&#xff0c;拖一个按钮过来&#xff0c;右边属性面用户可以自己改cursor属性。 代码方法&#xff0c;先拖一个按钮到界面上&#xff1a; #include <…

js:日期对象和dom节点

日期对象 事件对象在前端开发里经常用来表示日期&#xff1a; 可以获取当前系统的时间 实例化 使用new关键字来实例化一个对象&#xff1a; const date new Date()console.log(date); 获取当前时间 const date new Date(2008-8-8)console.log(date); 获取指定时间 写得…

minibatch时,损失如何记录

目录 minibatch时&#xff0c;损失如何记录 报错&#xff1a;UnboundLocalError: local variable coef referenced before assignment是什么回事 未溢出则不会报错&#xff0c;可以完整滴运行完成 indent 缩进 炫酷技能&#xff1a;一遍运行&#xff0c;一遍画图 实例1 解释…

力扣刷题:数组OJ篇(下)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 目录 1.轮转数组&#xff08;1&#xff09;题目描述…

5G学习笔记之PNI-NPN

目录 1. 概述 2. CAG 2.1 CAG ID 2.2 CAG信息配置 3. 网络选择/网络重选&#xff0c;小区选择/小区重选 4. 接入和拥塞控制 1. 概述 PNI-NPN&#xff0c;Public Network Integrated NPN&#xff0c;公共网络集成的非公共网络&#xff0c;依赖于PLMN网络&#xff0c;使用 CAG&am…

el-table 自定义表头颜色

第一种方法&#xff1a;计算属性 <template><div><el-table:data"formData.detail"border stripehighlight-current-row:cell-style"{ text-align: center }":header-cell-style"headerCellStyle"><el-table-column fixed…

C#标识符和关键字

本文将学习两个重要的基本概念&#xff1a;标识符和关键字。 1. 标识符 我们继续秉承"从实践中学习"的理念&#xff0c;先来看一段代码&#xff0c;如代码清单3-1所示。 代码清单3-1 标识符 using System;namespace ProgrammingCSharp4 {class IdentifierSample{…

怎么管理电脑usb接口,分享四种USB端口管理方法

怎么管理电脑usb接口&#xff0c;分享四种USB端口管理方法 USB接口作为电脑重要的外部接口&#xff0c;方便了数据传输和设备连接。 然而&#xff0c;不加管理的USB接口也可能带来安全隐患&#xff0c;例如数据泄露、病毒传播等。 因此&#xff0c;有效管理电脑USB接口至关重…

从 TiDB 学习分布式数据库测试

前言 最近在研究数据库正确性测试相关的内容&#xff0c;恰好看到TiDB数据库在这方面的工作&#xff0c;很受启发&#xff0c;故写此文章。 推荐下一些TiDB官方好文章&#xff1a; 《分布式系统测试那些事儿 – 理念》https://cn.pingcap.com/blog/distributed-system-test-…

尚硅谷Vue3入门到实战 —— 04 OptionsAPI 与 CompositionAPI

我们看一下上一节的代码&#xff0c;如下&#xff1a; <template><div class"person"><h2>姓名&#xff1a; {{ name }}</h2><h2>年龄&#xff1a; {{ age }}</h2><button click"changeName">修改名字</but…

【物联网原理与运用】知识点总结(上)

目录 名词解释汇总 第一章 物联网概述 1.1物联网的基本概念及演进 1.2 物联网的内涵 1.3 物联网的特性——泛在性 1.4 物联网的基本特征与属性&#xff08;五大功能域&#xff09; 1.5 物联网的体系结构 1.6 物联网的关键技术 1.7 物联网的应用领域 第二章 感知与识别技术 2.1 …

Nginx:会话保持

会话保持 是指在负载均衡环境中,确保来自同一用户的多个请求都发送到同一个后端服务器。这通常用于那些需要记住用户状态或上下文的应用程序,例如购物车、登录状态等。 会话保持的重要性 用户体验:保证用户在整个会话期间的一致性体验,避免因不同服务器间的数据不同步导致…

SEO内容优化:如何通过用户需求赢得搜索引擎青睐?

在谷歌SEO优化中&#xff0c;内容一直是最重要的因素之一。但要想让内容真正发挥作用&#xff0c;关键在于满足用户需求&#xff0c;而不是简单地堆砌关键词。谷歌的算法越来越智能化&#xff0c;更注重用户体验和内容的实用性。 了解目标用户的需求。通过工具如Google Trends…