图解用户登录验证流程,写得太好了!

打印 上一主题 下一主题

主题 902|帖子 902|积分 2706

原文:juejin.cn/post/7025768845075808286
前言

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

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

流程解读

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

  • 填写手机号
  • 发送验证码
  • 填写验证码
  • 勾选新用户自动注册
服务端-用户验证

  • 验证账号验证码是否正确
  • 验证用户是否存在(不存在出初始化用户信息)
  • 完成验证生成token
  • 将token返回给客户端
用户信息设计


验证流程图解


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

  • 获取验证码接口,给手机号发送验证码并设置验证码缓存,设置过期时间;
  • 登录接口,提交手机号及验证码,读取缓存进行匹配验证,成功则生成token返回给客户端,客户端登录成功,登录后请求头携带token进行业务请求即可。
关于token过期时间

通常我们token的过期时间是根据客户端的类型来定义的,app的过期时间会更长一些(通常一个星期),web端过期时间以小时为单位,如果控制过期时间可以将web登录和app登录拆分为两个接口(能够分流,接口压力更小),或者是根据请求头信息进行判断即可,是移动端就设置7天,是web端就设置两小时。
关于业务请求token验证

登录成功后,客户端每次请求都会携带token,通常我们会有一个网关来进行token验证,网关用于登录验证的核心就是登录成功后写入的token作为key,值为用户基础信息的缓存,图解如下:

验证成功后,重写内部请求头,将用户的的id,账号,昵称信息放入请求头中,这样可以方便业务系统获取当前操作用户信息以及权限控制等等
关于登出操作

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

通常匿名请求放行有两种方案,

  • 授权token,为token设置单位时间内请求次数;
  • 配置路径放行规则,对请求接口路径进行正则匹配,符合正则规则的进行放行
方案1:授权token,限制单位时间请求次数

优点就是虽然是免登录接口,但是接口的操作对象可以追溯,请求次数可控,避免被非法利用;缺点就是需要更多的编码及配置工作
技术实现


  • 提供一个授权token管理页面,主要管理token使用者,token的值,单位时间访问次数(如每分钟60次)
  • 增删改查,将授权token存放到缓存中,使用map进行存储,key为token,值为每分钟访问次数
  • 单位时间计数缓存,过期时间为1分钟
这时候我们需要在上面的验证流程图基础上进行升级

请求次数检查代码实现

[code]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请求限制缓存 */@Componentpublic class AuthTokenRequestLimitCache {    @Autowired    private RedisTemplate 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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

知者何南

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表