文章目录
前言
相信大伙小时候都看过洛洛历险记,里面的令牌机制很有意思,给我印象最深的就是能源之城的令牌,因为时光之城下面藏了很多能源紫水晶,那么好了。开始讲解今天的登录验证机制吧
1.cookie验证登录
1.1 cookie是什么
场景导入:今天猛虎王要去攻打雷霆殿,雷霆殿的机制是这样的(虚构):雷霆殿可以用本城的武器验证是否为本城的人,猛虎王拿到了一把急先锋的戟,于是就把城门打开了。
以上的故事里面:雷霆殿就相当于浏览器,因为急先锋的戟就是雷霆殿的,所以可以这样理解cookie就是戟。
简单记:cookie就是一种小型的文本文件,存储在浏览器中,记住这个就够了。
1.2为什么可以使用cookie进行验证登录
cookie是为了辨别用户身份。由于http是无状态的协议,服务器端不会记得是谁来向他发来的请求。但是我们需要一个唯一标识来验证用户,所以cookie就派上用场了。
具体的机制就是:如果服务器需要记录用户状态,服务器会在响应信息中包含一个Set-Cookie的响应头,客户端会根据这个响应头存储Cookie信息。再次请求服务器时,客户端会在请求信息中包含一个Cookie请求头,而服务器会根据这个请求头进行用户身份、状态等较验。
1.3 使用场景
一般在ssm项目中配合使用
- 创建cookie的验证方式
@Controller public class LoginController { @PostMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, HttpServletResponse response) { // 假设用户名和密码验证通过 if (username.equals("example") && password.equals("password")) { // 创建Cookie Cookie cookie = new Cookie("user", username); cookie.setMaxAge(3600); // 设置Cookie的过期时间,这里设置为1小时 cookie.setPath("/"); // 设置Cookie的作用范围 // 将Cookie添加到响应中 response.addCookie(cookie); return "redirect:/home"; // 登录成功后重定向到主页 } else { return "redirect:/login"; // 登录失败后重定向到登录页面 } } }
- 进行验证
@GetMapping("/home") public String home(HttpServletRequest request, Model model) { // 从请求中获取Cookie Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals("user")) { String username = cookie.getValue(); // 获取Cookie中存储的用户名 model.addAttribute("username", username); break; } } } return "home"; // 返回主页视图
缺点:根据场景就可以看到了,单纯用cookie非常不安全的。雷霆殿要是真的这样干,城主那可真是2b了。
可以罗列一个表格:
缺点 | 说明 |
---|---|
安全性 | Cookie存储在客户端,可能面临被窃取或篡改的风险。 |
CSRF攻击 | Cookie验证登录容易受到跨站请求伪造攻击,攻击者可以利用用户的Cookie进行未经授权的操作。 |
跨域访问限制 | Cookie在跨域场景下受到限制,仅在同一域名或子域名下有效。 |
隐私问题 | Cookie存储用户信息,可能引发隐私问题。尽管有一些安全措施,但仍需谨慎处理。 |
扩展性 | 如果需要扩展或更改身份验证机制,可能需要面临迁移用户会话的挑战,特别是对于已使用Cookie的大量用户。 |
2.session验证登录
2.1什么是session
场景导入:洛洛最喜欢去时光之城了,因为他晚上怕黑,要去时光之城找霹雳火,霹雳火没办法,给他录了一个脸,可以扫脸识别进入城门。好!我们的session,准确的来说是时光之城里面的脸型数据中洛洛的脸,记住是城门数据中洛洛的脸! 这个城门就相当于服务器,session的保存在服务器中的。请求来了,我们如果能从城门中获取到你的脸,我们就可以让你进去,而且会保存你的进度,你的喜好。你扫脸进来 直接给你送到霹雳火那里了。
简单记:session是保存在服务器中,用户存储和跟踪用户的会话信息,可以保存一段时间!知道这些就够了。
- tip:简单理解cookie和session之间的关系
可以把cookie跟session理解为:餐馆的餐牌 和 个人定制的餐桌
首先,当我们进入一个网站时,服务器会给我们分配一个唯一的标识号,就像餐牌上的编号,这就是Cookie。服务器会把这个Cookie发给我们的浏览器,浏览器会把Cookie保存下来。
接下来,当我们在这个网站上进行操作,比如登录,这些操作会产生一些数据,比如用户名、购物车内容等。这些数据就像是我们在饭店点的菜,而这些数据会被存储在Session中,就好像在服务员为我们准备的私人餐桌上放着我们点的菜。
每当我们发送一个请求给服务器,浏览器都会自动把保存的Cookie携带给服务器,就像我们手上拿着餐牌去点菜。服务器通过Cookie上的标识号(编号),就知道这个请求是哪个用户发来的。服务器接收到请求后,会根据Cookie上的标识号找到对应的Session,就像服务员根据餐牌上的编号,知道我们要去的是哪个餐桌。然后服务器就可以从Session中取出之前存储的数据,就像服务员把菜端到我们的桌子上供我们享用。
2.1 举例:session的登录验证机制
@Controller
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public String login(HttpServletRequest request, @RequestParam String username, @RequestParam String password) {
// 进行登录验证逻辑
if (userService.authenticate(username, password)) {
// 登录成功,将用户信息保存到Session中
User user = userService.getByUsername(username);
request.getSession().setAttribute("user", user);
return "redirect:/home";
} else {
// 登录失败
return "redirect:/login";
}
}
}
// 验证机制
@GetMapping("/home")
public String home(HttpServletRequest request) {
// 检查Session中是否存在已登录的用户
User user = (User) request.getSession().getAttribute("user");
if (user != null) {
// 已登录,渲染首页
return "home";
} else {
// 未登录,跳转至登录页面
return "redirect:/login";
3.基于Token的登录验证机制
3.1 什么是token
在做项目的时候,经常能碰到基于token的验证,那到底什么是token?
简单记:token就是令牌,就是时光之城的令牌。没有令牌谁来都不好使,城门只认令牌不认人,你就算密码输入正确了,没有令牌也进不去!
3.2 什么是JWT
我们在登录验证的时候经常可以看到一个词汇:JWT,所以它到底是什么
先说结论:JWT(JSON Web Token)就是一种常用的Token,WT由三个部分组成:头部、载荷和签名
- 头部(Header)包含令牌的类型和密钥算法等信息。
- 载荷(Payload)包含了一些有关你身份和权限的信息,比如你的用户名、角色或其他自定义数据。
- 签名(Signature)是用服务器的密钥对头部和载荷进行加密生成的,用来确保令牌没有被篡改。
当服务器接收到带有JWT的请求时,它会解析令牌并验证签名。如果签名验证通过,服务器就知道这个令牌是有效的,并且可以根据其中的信息判断你的身份和权限,从而进行相应的操作。
举例:
// 获取 Token
public static String generateToken(Long userId) throws Exception {
// 使用RSA256算法,并传入公钥和私钥
Algorithm algorithm = Algorithm.RSA256(RSAUtil.getPublicKey(), RSAUtil.getPrivateKey());
// 创建一个Calendar实例并设置为当前时间
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
// 在当前时间上添加1小时,得到JWT的过期时间
calendar.add(Calendar.HOUR, 1);
// 生成JWT
String token = JWT.create()
.withKeyId(String.valueOf(userId)) // 设置JWT的KeyId,用于标识唯一性
.withIssuer(ISSUER) // 设置JWT的发行者
.withExpiresAt(calendar.getTime()) // 设置JWT的过期时间
.sign(algorithm); // 使用指定的算法对JWT进行签名
// ----------------------------------------------------------------------
// 验证Token
public static Long verifyToken(String token) {
try {
// 使用RSA256算法,并传入公钥和私钥
Algorithm algorithm = Algorithm.RSA256(RSAUtil.getPublicKey(), RSAUtil.getPrivateKey());
// 创建JWT验证器
JWTVerifier verifier = JWT.require(algorithm).build();
// 验证JWT并解码
DecodedJWT jwt = verifier.verify(token);
// 从解码后的JWT中获取KeyId,然后将其转换为Long类型的userId
String userId = jwt.getKeyId();
return Long.valueOf(userId);
} catch (TokenExpiredException e) {
throw new ConditionException("sorry", "token过期!");
} catch (Exception e) {
throw new ConditionException("非法用户token!");
}
}
以上就是我总结的目前遇到过的登录验证,大哥大姐如果有别的验证方法,或者文章中有错误的,还望指正。