day12-SpringBootWeb 登录认证

一、登录功能

在这里插入图片描述
在这里插入图片描述

@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 问题分析

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

在这里插入图片描述
那应该怎么来实现登录校验的操作呢?具体的实现思路可以分为两部分:

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

登陆标记涉及到 web 开发中的 会话技术

统一拦截技术现实方案也有两种:

  1. Servlet 规范中的 Filter 过滤器
  2. Spring 提供的 interceptor 拦截器

2 会话技术

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

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

会话跟踪方案:

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

2.1 方案一 - Cookie

在这里插入图片描述

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

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

  1. 响应头 Set-Cookie :设置Cookie数据的
  2. 请求头 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();}
}

2.2 方案二 - 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);}
}

2.3 方案三 - 令牌技术

在这里插入图片描述

3 JWT 令牌

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

3.1 介绍

  • 全称:JSON Web Token (https://jwt.io/)
  • 定义了一种简洁的、自包含的格式,用于在通信双方以 json 数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

组成:

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

在这里插入图片描述

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

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

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

3.2 生成和校验

        <!--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);}
}

注意事项:

  1. JWT 校验时使用的签名秘钥,必须和生成 JWT 令牌时使用的秘钥是配套的。
  2. 如果 JWT 令牌解析校验时报错,则说明 JWT 令牌被篡改 或 失效了,令牌非法。

3.3 登录下发令牌

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;}
}
@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令牌),后续的每一次请求当中,都会将这个令牌携带到服务端。
在这里插入图片描述

4 过滤器 Filter

4.1 快速入门

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

Filter 快速入门 步骤:

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

4.2 Filter 详解

4.2.1 执行流程

在这里插入图片描述
在这里插入图片描述

4.2.2 拦截路径

Filter 可以根据需求,配置不同的拦截资源路径:
在这里插入图片描述

4.2.3 过滤器链
  • 介绍:一个 web 应用中,可以配置多个过滤器,这多个过滤器就形成了一个 过滤器链
  • 顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。

在这里插入图片描述

4.3 登录校验 - Filter

在这里插入图片描述

步骤

  1. 获取请求url。
  2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行。
  3. 获取请求头中的令牌(token)。
  4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
  5. 解析token,如果解析失败,返回错误结果(未登录)。
  6. 放行。
@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);}
}

5 拦截器 Interceptor

5.1 快速入门

  • 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring 框架中提供的,用来动态拦截控制器方法的执行。
  • 作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

在这里插入图片描述

Interceptor 快速入门 步骤:

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

在这里插入图片描述

5.2 Interceptor 详解

5.2.1 拦截路径

在这里插入图片描述

5.2.2 执行流程

在这里插入图片描述
在这里插入图片描述

    Filter 与 Interceptor 区别
  • 接口规范不同:过滤器需要实现 Filter 接口,而拦截器需要实现 HandlerInterceptor 接口。
  • 拦截范围不同:过滤器 Filter 会拦截所有的资源,而 Interceptor 只会拦截 Spring 环境中的资源。

5.3 登录校验- Interceptor

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法运行前运行, 返回true: 放行, 放回false, 不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {//1.获取请求url。String url = req.getRequestURL().toString();log.info("请求的url: {}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。if(url.contains("login")){log.info("登录操作, 放行...");return true;}//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 false;}//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 false;}//6.放行。log.info("令牌合法, 放行");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("afterCompletion...");}
}

三、异常处理(全局异常处理器)

  出现了异常,该如何处理?
  1. 方案一:在所有 Controller 的所有方法中进行 try…catch 处理
    缺点:代码臃肿(不推荐)
  2. 方案二:全局异常处理器
    好处:简单、优雅(推荐)

在这里插入图片描述
在这里插入图片描述

@RestControllerAdvice = @ControllerAdvice + @ResponseBody

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

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

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

相关文章

负阻尼振荡器仿真模拟

负阻振荡器&#xff08;Negative resistance oscillator&#xff09;是利用负阻器件抵消回路中的正阻损耗&#xff0c;产生自激振荡的振荡器。由于负阻器件与回路仅有两端连接&#xff0c;故负阻振荡器又称为“二端振荡器”。 阻尼是指阻碍物体的相对运动、并把运动能量转化为…

NVIDIA 推出地球-2云平台,使用AI超级计算机的模拟技术,预测整个地球的气候变化

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

new mars3d.layer.GeoJsonLayer({的pupup配置参考

new mars3d.layer.GeoJsonLayer({的pupup配置可选项以及相关效果参考&#xff1a; 说明&#xff1a;popup按属性字段配置&#xff0c;可以是字符串模板或数组 1.popup仅配置{type}{name}等属性的的时候&#xff0c;指显示json文件内数据的type与name&#xff0c;效果如下 相关…

MyBatis核心配置文件:解锁数据之美的密码

MyBatis&#xff0c;这位编程的诗人&#xff0c;通过其独特的核心配置文件&#xff0c;为我们描绘出一幅数据之美的画卷。本篇博客将带你深入探讨MyBatis核心配置文件的奥秘&#xff0c;让你能够更好地理解和运用这个优雅的数据持久化框架。 最近想搞私域&#xff0c;欢迎各位…

【MySQL】8. 基本查询(update/delete/聚合/分组)

表的删改 3. Update 语法&#xff1a; UPDATE table_name SET column expr [, column expr ...] [WHERE ...] [ORDER BY ...] [LIMIT ...]对查询到的结果进行列值更新 案例&#xff1a; 3.1 将孙悟空同学的数学成绩变更为 80 分 -- 更新值为具体值 -- 查看原数据 SELECT…

开发指南-1:编码技巧与规范开始

目录 实例 1.使用对象代替if及switch 2.使用Array.from快速生成数组 3.使用router.beforeEach来处理跳转前逻辑 4.使用v-if来优化页面加载 5.路由跳转尽量使用name而不是path 6.使用key来优化v-for循环 7.使用computed代替watch 8.统一管理缓存变量 9.使用setTimeout…

【深度学习】训练Stable Diffusion环境

仓库&#xff1a; https://github.com/bmaltais/kohya_ss.git 基础镜像&#xff1a; from kevinchina/deeplearning:sdxllighting_trt_nginx_002api docker run --net host --gpus device0 -e APIWORKS1 -it t1:t1 bash构建环境&#xff1a; sudo -i git clone https://git…

springboot291校园疫情防控系统

校园疫情防控系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统校园疫情防控信息管理难度…

Source Insight关于复制一段代码会自动添加空格或者Tab键的配置取消

Source Insight关于复制一段代码会自动添加空格或者Tab键的配置取消&#xff0c;这个情况在我们复制代码的时候对格式非常不友好&#xff0c;解决办法如下。 如下&#xff0c;我们可以设置相关配置&#xff1a; 设置完成后&#xff0c;然后再去复制&#xff0c;可以看到就没有相…

网络编程:包头分析

一、以太网头 以太网中封装了源mac地址以及目的mac地址&#xff0c;还有ip类型&#xff0c;以太网又称为mac头 0X0800 只接收发往本机的mac的ipv4类型的数据帧 0X0806 只接收发往本机的ARP类型的数据帧 0x8035 只接受发往本机的RARP类型的数据帧 0X0003 接收发往本机的MAC所…

十八、软考-系统架构设计师笔记-真题解析-2022年真题

软考-系统架构设计师-2022年上午选择题真题 考试时间 8:30 ~ 11:00 150分钟 1.云计算服务体系结构如下图所示&#xff0c;图中①、②、③分别与SaaS、PaaS、IaaS相对应&#xff0c;图中①、②、③应为( )。 A.应用层、基础设施层、平台层 B.应用层、平台层、基础设施层 C.平…

Jenkins 一个进程存在多个实例问题排查

Jenkins 一个进程存在多个实例问题排查 最近Jenkins升级到2.440.1​版本后&#xff0c;使用tomcat​服务部署&#xff0c;发现每次定时任务总会有3-4个请求到我的机器人上&#xff0c;导致出现奇奇怪怪的问题。 问题发现 机器人运行异常&#xff0c;总有好几个同时请求的服务。…

C++ 模板入门详解

目录 0. 模板引入 1.函数模板 1. 函数重载的缺点 2. 函数模板的概念和格式 2. 函数模板的实例化 2.1 隐式实例化&#xff1a;让编译器根据实参推演模板参数的实际类型 2.2 显式实例化&#xff1a;在函数名后的<>中指定模板参数的实际类型 2.3 函数模板参数的匹…

return code 1 from org.apache.hadoop.hive.ql.ddl.DDLTask

Bug信息 Error: Error while compiling statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.ddl.DDLTask (state=08S01,code=1)Bug产生的代码 修复hive表分区: msck repair table xxxBug原因排查 分区数量过大 这个是网上查看的说如果一次…

单身狗誓必脱单协会群(单身男女可进)

甜甜的恋爱&#xff0c;单身男女可进&#xff0c;谢绝己婚人士和海王进入&#xff01; 发送内容: "单身人士", 申请进群

【C++】—— 装饰器模式

目录 &#xff08;一&#xff09;什么是装饰器模式 &#xff08;二&#xff09;为什么要使用装饰器模式 &#xff08;三&#xff09;装饰器模式的实现步奏 &#xff08;四&#xff09;代码示例 &#xff08;五&#xff09;装饰器模式优缺点 &#xff08;一&#xff09;什么…

安科瑞保护测控产品在新能源行业中应用【峰谷套利 动态扩容 需求侧响应】

背景 2 月 10 日发布《关于完善能源绿色低碳转型体制机制和措施的意见》明确&#xff0c;鼓励建设源网荷储一体化、多能互补的智慧能源系统和微电网。 分布式光伏优势 近年来&#xff0c;随着光伏产业规模不断扩大&#xff0c;技术迭代升级不断加快&#xff0c;智能制造迅速推…

电脑照片分辨率怎么调?这款dpi修改工具好用

许多考试平台在上传证件照片的时候&#xff0c;大多都会对图片分辨率有具体要求&#xff0c;但是如果遇上手上的图片分辨率达不到要求&#xff0c;那么怎么改图片分辨率呢&#xff1f;可以利用专业的dpi修改工具来处理&#xff0c;比如今天分享的就是一个在线修改图片分辨率的方…

【漏洞复现】6.Struts2 S2-061 远程命令执行漏洞(CVE-2020-17530)复现与分析

文章目录 1. 预备知识2. 漏洞复现2.1 漏洞介绍2.2 漏洞原理分析2.2.1 Apache Struts2架构2.2.2 OGNL语法介绍2.2.3漏洞原理 2.3 漏洞复现2.3.1 靶场搭建2.3.2 漏洞探测2.3.3 漏洞利用2.3.4 POC分析 2.4 漏洞修复 1. 预备知识 Struts是一个用于开发Java EE网络应用程序的开放源代…

如何用SCSS制作小铃铛振动/震动/摇晃/晃动的特效/效果?

放大了看效果 ​​​​​​​​​​​​​​ // 摇晃小铃铛振动/震动/摇晃/晃动的特效/效果---------------------------------------- [sg-shaking] {display: inline-block;transform-origin: center top;animation: sg-shaking 1s alternate forwards; }keyframes sg-shaki…