tp5.1使用【redis】缓存【token】实现APP验证

1.用户在登录时创建token并且存储到redis中,同时返回给前端。将uid传过去是因为redis的name使用uid,值为token。

   $token=token::token($result['u_id']);

2. 自定义生成token代码,以及封装加密解密函数,我这里token设置时间为6个月

<?php


namespace app\common\token;


use app\common\model\User as ModelUser;
use think\facade\Cache;
use think\facade\Config;

class token
{
    public static function token($userid)
    {
        $key=Config::get('key');
        $s=self::authcode($userid,'ENCODE',$key,'');
        /*设置缓存*/
        self::setToken($s,$userid);
        return $s;
    }
    public static function setToken($token,$user_id)
    {
        /*设置6个月过期*/
        Cache::store('redis')->set($user_id,$token,15552000);
    }

    public static function check($token)
    {
        if (empty($token)){
            return ['code'=>20005,'msg'=>'参数错误'];
        }
           //全局key,在app.php中设置
        $key=Config::get('key');
        $s=self::authcode($token,'DECODE',$key,'');
        /*根据userid 获取token*/
        $is_has=Cache::store('redis')->get($s);
        if ($is_has){
            /*表示在时间内,再次比较参数是否正确*/
            if ($token==$is_has){
                return ['code'=>20000,'msg'=>'验证成功'];
            }else{
                return['code'=>20002,'msg'=>'身份验证失败,请重新登陆'];
            }
        }else{
            return ['code'=>20001,'msg'=>'登录过期了,请重新登录'];
        }
    }
     //加密函数
     public static function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
        // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
        $ckey_length = 4;
        // 密匙
        $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);

        // 密匙a会参与加解密
        $keya = md5(substr($key, 0, 16));
        // 密匙b会用来做数据完整性验证
        $keyb = md5(substr($key, 16, 16));
        // 密匙c用于变化生成的密文
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
        // 参与运算的密匙
        $cryptkey = $keya.md5($keya.$keyc);
        $key_length = strlen($cryptkey);
        // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),
        //解密时会通过这个密匙验证数据完整性
        // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :  sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
        $string_length = strlen($string);
        $result = '';
        $box = range(0, 255);
        $rndkey = array();
        // 产生密匙簿
        for($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }
        // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
        for($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        // 核心加解密部分
        for($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            // 从密匙簿得出密匙进行异或,再转成字符
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }
        if($operation == 'DECODE') {
            // 验证数据有效性,请看未加密明文的格式
            if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&  substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        } else {
            // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
            // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
            return $keyc.str_replace('=', '', base64_encode($result));
        }
    }
}

3. 配置基类控制器

<?php


namespace app\common\controller;
use app\common\token\token;
use think\Controller;



class Base extends Controller
{
    protected $user_id = NULL,$encryption = null;
    /*理论上来说查询你是不需要加token的*/
    protected $noNeedLogin = ['login','register'];   //不需要验证的接口

    public function initialize(){
        $token=request()->header('token');    //从header里获取token,'token'是前端的参数名
        if ($this->noNeedLogin){     //检查不需要token验证的接口
            $controller=request()->action();
            if (in_array($controller,$this->noNeedLogin)){
                return true;
            }
        }
        $s=token::check($token);
        //检查token
        if ($s['code']!=20000){
            $this->error($s['msg']);
        }
        return true;
    }
}

4.使用的时候页面继承Base控制器即可,会先进行token验证

5.前端正常带token访问即可

                                                             有不足的请地方多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉臣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值