用洛洛历险记来解释登录验证机制

前言

相信大伙小时候都看过洛洛历险记,里面的令牌机制很有意思,给我印象最深的就是能源之城的令牌,因为时光之城下面藏了很多能源紫水晶,那么好了。开始讲解今天的登录验证机制吧

《洛洛历险记》再度出圈,却不是一件好事,过度玩梗恐伤了作品_举报_旋风_闪电

1.cookie验证登录

1.1 cookie是什么

img

场景导入:今天猛虎王要去攻打雷霆殿,雷霆殿的机制是这样的(虚构):雷霆殿可以用本城的武器验证是否为本城的人,猛虎王拿到了一把急先锋的戟,于是就把城门打开了。

以上的故事里面:雷霆殿就相当于浏览器,因为急先锋的戟就是雷霆殿的,所以可以这样理解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的大量用户。

img

2.session验证登录

2.1什么是session

img

场景导入:洛洛最喜欢去时光之城了,因为他晚上怕黑,要去时光之城找霹雳火,霹雳火没办法,给他录了一个脸,可以扫脸识别进入城门。好!我们的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

img

我们在登录验证的时候经常可以看到一个词汇: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!");
    }
}

以上就是我总结的目前遇到过的登录验证,大哥大姐如果有别的验证方法,或者文章中有错误的,还望指正。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值