关于java:图解用户登录验证流程写得太好了

12次阅读

共计 2869 个字符,预计需要花费 8 分钟才能阅读完成。

原文:juejin.cn/post/7025768845075808286

前言

本文通过图示及代码的形式介绍用户登录流程及技术实现,内容包含用户登录,用户验证,如何获取操作用户的信息以及一些黑名单及匿名接口如何免验证相干的实现。

业务图解

对于用户登录来说、波及到了用户注册、登录验证几个方面,通过流程图演示如何解决(新用户 / 老用户)登录

流程解读

客户端 - 登录界面(通常手机验证码登录)

  1. 填写手机号
  2. 发送验证码
  3. 填写验证码
  4. 勾选新用户主动注册

服务端 - 用户验证

  1. 验证账号验证码是否正确
  2. 验证用户是否存在(不存在出初始化用户信息)
  3. 实现验证生成 token
  4. 将 token 返回给客户端
用户信息设计

验证流程图解

登录验证流程波及到了两个接口,两个缓存。

  1. 获取验证码接口 ,给手机号发送验证码并设置验证码缓存,设置过期工夫;
  2. 登录接口 ,提交手机号及验证码,读取缓存进行匹配验证,胜利则生成 token 返回给客户端,客户端登录胜利,登录后申请头携带 token 进行业务申请即可。
对于 token 过期工夫

通常咱们 token 的过期工夫是依据客户端的类型来定义的,app 的过期工夫会更长一些(通常一个星期),web 端过期工夫以小时为单位,如果管制过期工夫能够将 web 登录和 app 登录拆分为两个接口(可能分流,接口压力更小),或者是依据申请头信息进行判断即可,是挪动端就设置 7 天,是 web 端就设置两小时。

对于业务申请 token 验证

登录胜利后,客户端每次申请都会携带 token, 通常咱们会有一个网关来进行 token 验证,网关用于登录验证的外围就是登录胜利后写入的 token 作为 key,值为用户根底信息的缓存,图解如下:

验证胜利后,重写外部申请头,将用户的的 id, 账号,昵称信息放入申请头中,这样能够不便业务零碎获取以后操作用户信息以及权限管制等等

对于登出操作

用户携带 token 申请登出接口,登出接口对 token 对应的缓存进行删除操作,返回 401 即可,客户端获取到 401 就会跳转到登录页面

对于匿名申请(免登录)

通常匿名申请放行有两种计划,

  1. 受权 token, 为 token 设置单位工夫内申请次数;
  2. 配置门路放行规定,对申请接口门路进行正则匹配,合乎正则规定的进行放行

计划 1:受权 token,限度单位工夫申请次数

长处就是尽管是免登录接口,然而接口的操作对象能够追溯,申请次数可控,防止被非法利用;毛病就是须要更多的编码及配置工作

技术实现

  1. 提供一个受权 token 治理页面,次要治理 token 使用者,token 的值,单位工夫拜访次数(如每分钟 60 次)
  2. 增删改查,将受权 token 寄存到缓存中,应用 map 进行存储,key 为 token,值为每分钟拜访次数
  3. 单位工夫计数缓存, 过期工夫为 1 分钟

这时候咱们须要在下面的验证流程图根底上进行降级

申请次数查看代码实现

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 受权 token 申请限度缓存
 */
@Component
public class AuthTokenRequestLimitCache {

    @Autowired
    private RedisTemplate<String, Integer> redisTemplate;

    private static final String AUTH_TOKEN_LIMIT_KEY_PREFIX = "auth_token_limit";

    /**
     * 申请次数 + 1 并查看是否超限
     *
     * @param token
     * @return 是否放行
     */
    public boolean incrementWithCheck(String token) {
        // 1. 获取 token 申请次数限度,获取为 null 代表受权配置已被批改,此 token 曾经不具备权限
        Integer limit = getLimit(token);
        if (limit == null) {return false;}
        // 2. 组装缓存 key,读取缓存
        String key = String.join(":", AUTH_TOKEN_LIMIT_KEY_PREFIX, token);
        Integer count = redisTemplate.opsForValue().get(key);
        // 3. 没有值代表一分钟内没有申请产生了
        if (count == null) {
            // 初始化值
            redisTemplate.opsForValue().increment(key);
            // 设置过期工夫
            redisTemplate.expire(key, 1L, TimeUnit.MINUTES);
            return true;
        }
        // 自增并获取以后值 大于限度的话 返回 false 网关过滤器返回提示信息(如申请过于频繁)Long inc = redisTemplate.opsForValue().increment(key);
        return inc <= limit;
    }

    /**
     * 获取限值
     *
     * @param token
     * @return
     */
    public Integer getLimit(String token) {Object limit = redisTemplate.opsForHash().get("auth_token_limit", token);
        return limit == null ? null : (Integer) limit;
    }
}

对于受权接口,通常是只容许 get 操作,对数据进行提交或者更新是不被容许的,当然这个是业务层面的,最终取决于零碎设计

计划 2:申请门路正则校验

咱们在网关的配置文件中减少匿名接口规定,申请到网关时,查看申请的门路是否合乎匿名接口规定,是则放行,不是则进行 token 校验,计划比较简单,只须要对网关进行解决即可。

对于黑名单

对于一个零碎来说,黑名单是最初一道关卡,所以为了平安咱们须要对问题用户进行黑名单操作,具体实现也比较简单

  1. 用户治理页面提供一个拉黑的按钮,拉黑后,这些用户的 id 会存储到一个 set 汇合中去
  2. 登录时候检查用户是否在黑名单中,是则回绝登录并提醒
  3. 如果用户曾经登录后进行拉黑操作,网关会在鉴权通过后检查用户是否在黑名单中,是则删除 token 对应缓存,返回 401,401 就会跳到登录页,步骤 2 就会进行拦挡。

总结

用户零碎是十分根底的零碎,然而很多程序员工作中可能并没有真正的参加到用户零碎的开发,通过此文能够对用户登录流程及配套性能有一个全面的理解。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿 (2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0