怎么自己做彩票网站,网站顶部地图代码怎么做,商城服务是什么软件,1cpu0.5g服务器用来做网站前言#xff1a;Servlet 【登录校验】这个功能技术的基础是【会话技术】#xff0c;那么在讲【会话技术】的时候必然要谈到【Cookie】和【Session】这两个东西#xff0c;那么在这之前必须要先讲一下一个很重要但是很多人都会忽略的一个知识点#xff1a;【Servlet】 什么是…前言Servlet 【登录校验】这个功能技术的基础是【会话技术】那么在讲【会话技术】的时候必然要谈到【Cookie】和【Session】这两个东西那么在这之前必须要先讲一下一个很重要但是很多人都会忽略的一个知识点【Servlet】 什么是Servlet Servlet是用java编写的应用在服务器端的程序对于它的定义“广义上”是一个个很大的【类】“狭义上”是【接口】 . Servlet容器是什么 我们经常听说的Tomcat、Weblogic......这些都是各种【Servlet容器】而【Servlet容器】就是Servlet的运行环境也可以理解是Servlet的引擎为请求和响应的这些操作提供网络服务。 那么我们知道我们运行网络服务的时候都要启动Tomcat服务器Tomcat来解析处理【请求】、【响应】并处理成报文信息但是这些服务器的缺点是底层代码写死了很不灵活而且有时处理完的数据格式也不够规范那么这时候就诞生了Servlet它被用来“扩展服务器的性能”它能够灵活的处理请求、响应数据并以规范形式返回。 那么说回Servlet其实最简单最简单的理解就是一个很大很规范的【类】它里面包含了很多其他【子类】准确来说是接口这些子类包括Cookie、Session、HttpServletRequest、HttpServletResponse、ServletConfig、ServletContext...... 。 那么这些【子类】里也写好了很详细、规范的各种处理网络服务的方法当我们需要处理一些网络服务逻辑的时候就需要调用Servlet里的【子类】的【实例化对象】的【方法】 打个比方处理前端客户端发送请求的数据并生成对应的请求头报文时就需要调用【HttpServletRequest】的实例化对象的方法 处理服务器端返回回去的响应头报文的时候就需要调用【HttpServletResponse】的实例化对象的方法......等等 。 那么现在我们重新来看一下B/S架构浏览器客户端与服务器端传输的流程 1、浏览器客户端发送请求到服务器端 2、服务器端接收到信息交给Servlet 3、Servlet通过调用里面的一些子类的方法处理逻辑然后生成响应信息给回服务器 4、服务器将响应结果返回浏览器客户端 一、会话技术
1、何为会话
浏览器与服务器之间的一次连接就是一次会话 2、会话跟踪
【会话跟踪】就是识别多个请求是否来自于同一个浏览器然后在同一个浏览器的多个请求之间共享数据 3、会话跟踪方案:
浏览器与服务器之间的交互使用的是【http】协议但是【http】协议是无状态的也就是所有请求都是相互独立的并不能在多个请求之间共享数据
那么就有了这么几种【会话跟踪技术】 1、客户端会话跟踪技术:Cookie . 2、服务端会话跟踪技术:Session 。 3、token令牌技术JWT 这里不讲解HTTP是啥这里有一篇讲的比较详细HTTP 协议详解(史上最全)-CSDN博客
HTTP协议里的【请求头】和【响应头】的文章Request Headers 和Response Headers——请求头和响应头-CSDN博客
只需要知道HTTP协议是一个浏览器与服务器联系传输数据的超文本传输协议它两规定了一种传输数据的格式然后里面有【响应报文Response Headers】和【请求报文Request Headers】这两部分下面是简单讲解 【请求报文Request Headers】 前端通过【浏览器/客户端】发送请求传给【服务器】的数据信息 。 一个【请求报文Request Headers】里包括了【请求行】【请求头】【请求体】 【请求体】就是前端传过来的具体的数据信息 【请求头】是服务器获取客户端信息的一些依据用什么格式获取从哪个地址获取哪个浏览器发的...... 【响应头报文Reponse Headers】 【服务器】返回给【浏览器/客户端】的响应数据信息 一样一个【响应报文Response Headers】里也包括了【响应行】【响应头】【响应体】 【响应体】就是针对前端发来的请求数据而相应回去的具体数据值 【响应头】包含了服务器的响应讯息如http版本压缩方式响应文件类型文件编码等 1Cookie技术Cookie是一个Servlet里的“子类”
虽然每个请求和响应之间的Http协议是独立的但是Http协议的【请求头】和【响应头】支持携带【Cookie】这个信息那多个请求间就可以通过Cookie这个标识来获取用户信息数据 Cookie简单说就是存放在【客户端浏览器】的会话信息 —— Cookie是通过在【请求报文Request Headers】里的【请求头】处传递的 —— 传递关系是【客户端浏览器】——传Cookie——【服务器】 —— Set-Cookie是通过【响应报文Response Headers】里的【响应头】处传递的 —— 传递关系是【服务器】——返回Set-Cookie——【客户端浏览器】 简单用代码直观一点展示Cookie和Set-Cookie切记别记忆这些代码简单了解即可
Set-Cookie 【HttpServletResponse】这个接口的实现类是专门设置【响应报文】信息的切记要导入的包一定要选这个【javax.servlet.http】 . 然后【HttpServletResponse】的实现类对象的【.addCookie( )】方法能设置一个Cookie的值需要往里面传一个【Cookie对象】切记这个【Cookie对象】对应的类型必须也是【javax.servlet.http】 . 最后【Cookie对象】里数据形式是“键值对Keyvalue”:【namevalue】所以要传一个name参数、一个value值分别代表 “键” 和 “值” /*** 模拟【服务器】设置【用户的Cookie】的操作* param response* return*/
GetMapping(/setCookie)
public Result setCookie(HttpServletResponse response){//调用这个响应方法就能设置一个Cookie值Cookie对象里是【键值对】信息namevalueresponse.addCookie(new javax.servlet.http.Cookie(userName,岑梓铭));return Result.success();
} 怎么看效果 1、首先输入网址千万先别回车 2、摁F12打开网页检查然后再在网址那回车就会看到一个网络响应 3、单击它然后就能在【响应报文Response Header】处看到【Set-Cookie】 Cookie 【HttpServletRequest】这个接口的实现类是专门设置【请求报文】信息的切记要导入的包一定要选这个【javax.servlet.http】 . 然后【HttpServletRequest】的实现类对象的【.getCookies( )】方法能返回所有Cookie的值返回值是一个数组需要用一个【Cookie对象类型的数组】接收切记这个【Cookie对象】类型对应的类型必须也是【javax.servlet.http】 . 最后【Cookie对象】里数据形式是“键值对Keyvalue”:【namevalue】所以要获取Cookie数组里每一个Cookie的 “键”就要调用【Cookie对象】的【.getName( )】方法 GetMapping(/getCookie)
public Result getCookie(HttpServletRequest request){//发送请求后获取返回的【所有的Cookies】javax.servlet.http.Cookie[] cookies request.getCookies();//遍历所有Cookie如果有对应这个【键name】的就返回对应的【值value】for(javax.servlet.http.Cookie cookie : cookies){if(cookie.getName().equals( userName )){System.out.println(userName: 【 cookie.getValue() 】);}}return Result.success();
} 怎么看效果还是一样 1、首先输入网址千万先别回车 2、摁F12打开网页检查然后再在网址那回车就会看到一个网络响应 3、单击它然后就能在【响应报文Response Header】处看到【Set-Cookie】 缺点 1、移动端环境不是浏览器浏览器才有Cookie这玩意 . 2、用户可以随意自己设置禁用Cookie会用电脑的应该不用我解释浏览器设置那里有 . 3、Cookie不能跨域跨域就是【协议、IP/域名、端口】至少其中一样不一样就是两个域就存在跨域访问那么我们都知道前端、后端是分别部署到两个不同的服务器的不同服务器的地址肯定是不一样的浏览器在发请求、返回响应时必然会要访问前端和后端的两个服务器就会跨域 总结 2Session技术Session也是Servlet里的一个“子类”
Session的本质其实就是对Cookie的优化是存放在【服务器端】的会话信息 为什么说是Cookie的优化因为它的逻辑其实是这样 。 首先浏览器发请求产生一个会话然后服务器这边就立刻产生一个【Session会话信息】和一个对应这个Session会话信息的【sessionId】然后把【Session会话信息】存在服务器只会把【sessionId】存进Cookie通过Set-Cookie响应回给浏览器 。。 然后下次浏览器再次发送请求想获取这个【Session会话信息】的时候传递过去的是【装着sessionId的Cookie】然后服务器检查Cookie里的【sessionId】再到session里找有没有对应这个【sessionId】的【Session会话信息】找到了的话把【sessionId】和【Session会话信息】一起塞进【Cookie】返回给浏览器 模拟服务器【保存session】并【生成sessionId】的逻辑 /*** 模拟【服务器端】生成并响应回【session】的操作* param session* return*/
GetMapping(/setSession)
public Result setSession(HttpSession session){//打印一下当前session的哈希码值这个哈希码值代表指向了哪一个session会话是【整数】//但是注意区分这个不是sessionIdsessionId是HttpSession对象的唯一标识符是【字符串】log.info(session_hashCode: {},session.hashCode());//调用这个方法可以往session会话里存入一个数据然后对应生成一个sessionID并塞进Cookie里session.setAttribute(LoginName,岑梓铭);return Result.success();
} 模拟浏览器通过sessionId【接收session信息】的逻辑 /*** 模拟【浏览器】发请求后获得服务器生成的【session】的操作* param request* return*/
GetMapping(/getSession)
public Result getSession(HttpServletRequest request){//调用HttpServletRequest对象的getSession()方法可以获取到session会话对象HttpSession session request.getSession();//打印一下当前session的哈希码值这个哈希码值代表指向了哪一个session会话是【整数】log.info(session_hashCode: {},session.hashCode());//Session的getAttribute方法里面传入“键”参数就能返回对应的seesion会话对象里的具体值//逻辑是浏览器这边Cookie里只有sessionId然后通过Session的getAttribute方法把Cookie里的sessionId给到服务器端//最终经过服务器检测sessionId然后将session会话里对应“userName”的会话具体数据再塞进Cookie返回给浏览器Object userInfo session.getAttribute(LoginName);log.info(userInfo: {},userInfo);return Result.success(userInfo);
} 缺点 1、服务器集群情况下也就是连接多个服务器的情况下不同的服务器之间存着不同的会话信息那就算浏览器的Cookie里有sessionId那第二台服务器那里能靠第一台服务器seesion的 “钥匙” 来 “开“ 第二台服务器seesion的 “大门” 呢 . 2、session会话信息都存在服务器随着浏览器请求增多服务器内存越来越不够用 . 3、既然它还是基于Cookie优化而来的那必然也继承了Cookie的缺点 总结 3JWT令牌技术
——概念
JWT全称【Json Web Token】简单来说就是一长串带有【数字签名、签名算法、具体自定义信息......等等】json字符串每一次请求响应都会带着它通过计算来校验、得出其中的身份信息 一个JWT字符串主要包括三大部分 第一部分Header(头)记录令牌类型、名算法等。例如:{alg:HS256,type:JWT} 第二部分Payload(有效载荷)携带一些自定义信息、默认信息等。例如:{id:1,username:Tom} 第三部分Siqnature(签名)防止Token被篡改、确保安全性。将header、payload并加入指定秘钥通过指定签名算法计算而来。 而组成这个字符串的原理是 1、前面两部分是【Base64编码】是一种由【A-Z a-z 1-9 还有/】组成的来表示二进制数据的编码 。 2、最后一部分那一段是根据前面指定的一种【签名算法】计算后得到的编码 应用场景 其实很简单流程就是 1、浏览器发送请求到服务器 2、服务器拦截请求查看有没有token没有就拒绝访问数据并生成一个JWT令牌 3、下一次再来检查到有JWT令牌了那就校验JWT令牌对不对不对就拒绝访问对就开放访问权限。 生成JWT令牌的方法
1、引入依赖 在pom.xml文件引入下面依赖 !-- JWT令牌 --
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactIdversion0.9.1/version
/dependency 注意如果点了右上角的【maven刷新】按钮只后还是爆红又可能只是连接中央库下载安装这个依赖包的时候网络不好毕竟这些依赖都是在国外的公司的中央库那么控制台那会有一个 “蓝色” 的提示——“尝试使用 -U 标记强制更新快照运行 Maven导入”直接点它让Maven帮我们换个方案下载安装就行了 2、在Test类测试一下生成JWT令牌
只需要记住6步 1、先设置一个哈希表集合因为jwt令牌的【有效信息部分】要用【哈希表集合类型】接收 2、创建一个jwt的方法是【Jwts.builder( )】 3、一个Jwt令牌的第一部分是指定 “签名算法类型”、“签名密钥”那么【.signWith( )方法】就是设置jwt令牌第一部分。以我个人理解“签名算法类型” 就是指根据不同类型的不同算法“签名密钥” 就是以你自定义输入的一串字符串作为一个 “密钥”用你的这个 “签名密钥” 才能在解析jwt令牌时知道你要解析的是哪一个至于“签名算法类型”具体哪些类型有啥区别我也不知道尽量先都用HS256这个类型就行 4、一个Jwt令牌的第二部分是【有效荷载】也就是用户的一些【有效信息部分】【Jwts.addClaims( )】方法则是在创建一个jwt对象之后接收这个【有效信息部分】的方法接收【哈希表集合】类型数据 5、jwt令牌要有个【有效时间】就跟你们平时登录时的验证码一样不然的话没时间限制那不是留够了时间给黑客破解吗。【.setExiration( )】方法就是设置【有效时间】需要接受的是Date时间类型System.currentTimeMillis()是目前的系统时间加一个有效时间期限就行 6、jwt是一个对象要用【.compact( )】方法才能转化成【字符串】 Test
void testGenJWT(){//先设置一个哈希表集合因为jwt令牌的【有效信息部分】要用【哈希表集合类型】接收MapString , Object claims new HashMap(); //值用Object因为可能是数字、可能是字符串claims.put(id,1);claims.put(name,岑梓铭);String jwt Jwts.builder() //builder就是创建一个JWT令牌.signWith(SignatureAlgorithm.HS256,yjtlwkbz) //设置【签名算法的类型比如HS256】、【签名内容比如yjtlwkbz】.addClaims(claims) //有效荷载部分接收哈希表集合类型存入用户有效信息.setExpiration(new Date(System.currentTimeMillis() 3600*1000)) //设置有效时间1h3600秒 * 1000毫秒.compact(); //把结果生成字符串System.out.println(jwt);
} 然后提示几点 1、因为顶上的【SpringBootTest】注解会影响整个项目直接注释了然后点对应这个当前这个【Test】测试方法运行最快 . 2、如果刚刚编写生成jwt令牌代码时爆红爆错检查这几个问题 —— 报错classNotFoundException的下载jaxb-api依赖2.1版本版本别填错了 —— 使用Base64编码字符串长度至少为43位位数报错的可以把 “签名内容” 改成任意的大于等于43位的字符串比如我代码里的yjtlwkbz改成ahjahsdgaysdgkuywdgjwdbasbcjhcjasyasgkjjsh 。 3、还有有的人可能会出现【test】包下的test类class文件全变成java文件了没法运行右键也不能新建class类文件那可能是IDE出了点问题清楚IDE缓存再重新启动一次就行见下图 然后运行完成后我们把控制台生成的【jwt令牌】复制到这个网站可以查看解析我们的【jwt令牌】的信息JSON Web Tokens - jwt.io 解析JWT令牌的方法
更简单三步 1、【Jwts.parser( )】方法解析jwt令牌 2、【.setSigningKey( )】方法就是根据你前面生成jwt令牌时的那个【签名密钥】来 “打开解密大门” 3、【.parseClaimsJws( )】把刚刚生成的【jwt令牌】整个塞进去就能被解析了 注意别选成【.parseClaimsJwt( )】了这两是两个东西选下图这个 4、【.getBody( )】能够获取出【有效荷载】部分那些具体信息并封装在一个Claims类型对象 Test
void testGetJWT(){Claims claims Jwts.parser().setSigningKey(yjtlwkbz) //对应生成jwt的.signWith(SignatureAlgorithm.HS256,yjtlwkbz)那个密钥//对应刚刚运行生成的jwt令牌.parseClaimsJws(eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bKR5qKT6ZOtIiwiaWQiOjEsImV4cCI6MTcyMDQwOTg1Nn0.OmpQBJoP50BjjPnItLBGCmhgAVTcDzYGsTBMT7qohoE).getBody(); //获取有效荷载部分System.out.println(claims);
} 注意几点 1、有效信息最后要用一个Claims对象来接收 2、一个jwt令牌有时效和使用次效你如果超过了你设置的失效期限、或者已经运行执行了一次解析jwt令牌那么这串jwt令牌就作废了需要你再次运行【生成jwt令牌】然后再运行【解析jwt令牌】获取信息否则会报错 3、【.parseClaimsJws( )】别写成了【.parseClaimsJwt( )】 二、利用jwt令牌技术校验身份
现在我们学完了最先进的jwt令牌技术那么就来实践一下如何运用它。
1、先为了前后端请求响应方便封装好一个jwt令牌工具类 很简单我们前面已经知道怎么【生成】和【解析】jwt令牌了那么在封装工具类里只要改几点 / 1、【生成jwt令牌】的时候首先要接收一个前端传过来的装着用户有效信息的【哈希表集合】参数并最后要把生成的令牌字符串return出去 . 2、【解析jwt令牌】的时候需要接收生成的jwt字符串并把解析获得【有效荷载信息】return回前端 package com.czm.tliaswebmanagement.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;
import java.util.HashMap;
import java.util.Map;//别忘了加这个注解让类放入IOC容器
Component
public class JwtUtils {private static String signKey yjtlwkbz; //定义【签名密钥】是“yjtlwkbz”private static Long time (long)60*5 * 1000; //定义有效时间是5分钟/*** 接收前端有效信息生成jwt令牌并返回给前端* param claims* return*/public String generateJWT(MapString,Object claims){String jwt Jwts.builder() //builder就是创建一个JWT令牌.signWith(SignatureAlgorithm.HS256,signKey) //设置【签名算法的类型】、【签名内容】.addClaims(claims) //有效荷载部分接收哈希表集合类型存入用户有效信息.setExpiration(new Date(System.currentTimeMillis() time)) //设置有效时间.compact(); //把结果生成字符串return jwt;}/*** 接收前端传来的jwt令牌解析并返回有效荷载* param jwt* return*/public Claims parseJWT(String jwt){Claims claims Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();return claims;}
} 2、然后完成登录接口三层架构代码编写 1、首先根据接口文档规定来确定前端传入的是什么格式数据 比如这个文档以它为例子那么确定前端传入【JSON格式】的【用户登录信息】那么就要用一个Emp对象我前几篇一直用的案例员工对象来接收这些参数值然后用【RequestBody】解析JSON成对象。然后post请求跟接口是“/login”那就【PostMapping(/login)】 contrller 。 2、第二步在controller层调用service、并把刚刚解析的参数Emp传给serviceservice调用mapping进行sql查询根据这个【用户登录信息】参数查询完数据库之后返回结果再一级一级返回controller老生常谈的流程我就不细说了。 controllerr service mapping 。 3、然后在controller层再用一个【新的Emp对象】接收【查询完返回的结果】如果查询到结果就说明数据库有这个账户那么调用【JWT工具类】为这个账户【生成一个jwt令牌】生成jwt的逻辑在JWT工具类已经帮我们做好了我们只需要传一个【装有用户信息】的【Map哈希表集合类的参数】给JWT工具类就行了 。 4、最后在查询到账户的情况下将生成含有用户信息的JWT令牌返回给前端即可如果查不到信息就说明账户密码有误查无此人那就直接返回失败。 controller的完整代码其他的层的就不展示了
package com.czm.tliaswebmanagement.controller;import com.czm.tliaswebmanagement.pojo.Emp;
import com.czm.tliaswebmanagement.pojo.Result;
import com.czm.tliaswebmanagement.service.EmpService;
import com.czm.tliaswebmanagement.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;Slf4j
//RequestMapping(/emps)
RestController
public class EmpController {Autowiredprivate EmpService empService;//获取JWT令牌工具类Autowiredprivate JwtUtils jwtUtils;/*** 登录接口*/PostMapping(/login)public Result login(RequestBody Emp emp){log.info(传过来的员工账号密码信息{},emp);//先调用service查找数据库有无此账户Emp e empService.login(emp);//判断能否根据用户名、密码在数据库查到此人//有的话生成属于它的令牌并返回给他if(e ! null){//因为生成jwt令牌需要的是【哈希表集合】类型所以用一个【哈希表集合】装查到的员工信息MapString , Object claims new HashMap();//这里经过service、mapper查询回来的员工信息e获取出他的id、name、username作为有效荷载信息claims.put(id,e.getId());claims.put(name,e.getName());claims.put(username,e.getUsername());//调用jwt工具类生成jwt方法获取jwt令牌String jwt jwtUtils.generateJWT(claims);//然后把jwt令牌返回给前端return Result.success(jwt);}//那么如果数据库都没查到这个账户就说明账号密码输入错误返回错误就行了return Result.error(登陆失败查无此人);}
}然后我要解释一下这个jwt令牌到底在哪里传输
就在一个叫【token】的玩意里存着你可以理解为【token】是一张磁卡然后 jwt 就是类似这个磁卡的信号信息你用【token】这个磁卡刷门禁、刷刷卡机的时候把 jwt 信息传过去验证。
然后这个【token】可以放请求体、也可以是请求头不过一般都是放请求头 那么现在前端只要登陆成功就已经能获取到后端为之生成的jwt令牌了现在只需要下次再携带这个jwt令牌发送请求后端就可针对这个令牌进行判断是否给这个用户放行使用软件、网页了那么这就涉及到【过滤器filter】和【拦截器Interceptor】下一篇再讲