加密方式之自己正使用无状态加密内含实现代码

欢迎大家访问我的博客 blog.ayla1688.cool


### 传统加密方式-有状态加密

用户登录后,我们分配给用户一个token, 然后将token 放在redis中一份,放在数据库中一份; 当用户携带token 访问接口时,我们一般会做以下判断:
> token是否正确
> token是否过期

通过以上的判断,我们可以确认用户的有效性。这中间就涉及到一个问题,我们需要取出自己保存的token, 先从redis中获取,如果redis中key过期或者redis宕机,我们就要从数据库中获取,无论从哪获取都涉及到IO。 

这种方式就是有状态的加密。

### 无状态加密

用户登录之后,我们返回用户一些用于加密的字段, 用户访问接口时,使用接口入参,加密字段和固定字段key进行加密,生成不可你解析token ,一般使用md5加密, 服务器端拿到token,入参后, 通过同样的规则, 使用接口入参,加密字段和固定字段key进行加密得到tokenVerify, 对比token 和tokenVerify , 相同则用户有效,不同则用户无效。 无需访问redis和数据库。

这种方式就是无状态的加密。

###下面上代码,在实际应用中看下实现方式

首先我们有一个BaseController是基类控制器,做用户验证等基础工作
```
<?php
/**
 *
 * File Base
 * author mselect
 * DateTime 2019-12-01
 * @return
 */

namespace app\wxmini\controller;


use think\App;
use think\exception\HttpResponseException;
use think\Response;

class BaseController extends \think\Controller
{
    //用户ID
    protected $user_id = 0;
    //请求头
    protected $header = array(
        'Access-Control-Allow-Origin' => '*',
        'Access-Control-Allow-Headers' => 'X-Requested-With,Content-Type,Api-Token,Api-Version,Api-Timestamp,Api-User,Api-Sign',
        'Access-Control-Allow-Methods' => 'GET,POST,OPTIONS',
    );
    //original 准过滤白名单
    public $whiteOrigin = array();
    protected $whiteList = array();
    //api版本号
    protected $versionToKey = [
        '1.0.0' => '77fruit',
    ];

    protected $codeMark = [
        'SUCCESS' => 1,                 //返回成功
        'ERROR' => -1,                  //返回失败
        'NOMORE' => -50,                //没有要加载的更多数据
        'NODATA' => -100,               //没有数据
        'NOTLOGIN' => -1000,            //未登录
        'DATAERROR' => -2000,           //数据错误
        'SIGNEMPTY' => -2001,           //签名为空
        'SIGNERROR' => -2002,           //签名错误
        'LOGINERROR' => -2010,          //登陆失败
        'SECURITYERROR' => -10000,        //非法登陆
        'SYSTEMERROR' => -2333,           //系统错误
    ];


    public function __construct(App $app = null)
    {
        parent::__construct($app);
        if(in_array($this->request->action(), $this->whiteList)){
            return true;
        }

        $this->_checkPostData();
        $this->_initUser();
    }

    /**
     * 用户信息初始化
     * Function _initUser
     * author mselect
     * DateTime 2019-12-01
     */
    public function _initUser(){
        $token = (string)$this->request->header('Api-Token', '');
        $user_id = (string)$this->request->header('Api-User', 0);
        $timestamp = (string)$this->request->header('Api-Timestamp', '');
        $version = (string)$this->request->header('Api-Version', '');

        if( empty($this->versionToKey[$version])){
            $this->outPut('SECURITYERROR', '非法访问');
        }

        if($token != '' && $user_id >0 && $timestamp != '' && $version != ''){
            //均带着登陆所需参数
            $newMd5 = md5($this->versionToKey[$version] . $timestamp . $user_id . $version );

            if($newMd5 === $token){
                //符合登陆规则
                $this->user_id = $user_id;
            }
        }

    }


    /**
     * 检查Post数据
     * Function checkPostData
     * author mselect
     * DateTime 2019-12-01
     */
    private function _checkPostData(){
        $post = $this->request->post();
        $version = (string)$this->request->header('Api-Version', '');

        if( empty($post)){
            $string = '';
        }else {
            ksort($post);
            $data = [];
            foreach($post as $key=>$value){
                $data[] = $key ."=". $value;
            }
            $string = implode('&', $data);
        }

        $sign = md5($string . "&key=" . $this->versionToKey[$version]);

        $signature = (string)$this->request->header('Api-Sign', '');
        if( $signature == ''){
            $this->outPut('SIGNEMPTY', '签名参数错误');
        }


        if( $signature !== $sign){
            $this->outPut('SIGNERROR', '签名错误');
        }

        return true;
    }


    /**
     * 统一输出
     * Function outPut
     * author mselect
     * DateTime 2019-12-01
     */
    public function outPut($code, $msg='', $data = []){
        $result = array(
            'code' => $this->codeMark[$code],
            'msg' =>  $msg,
            'data' => $data,
        );
        $type                                   = $this->getResponseType();
        $response                               = Response::create($result, $type)->header($this->header);
        throw new HttpResponseException($response);
    }

    /**
     * 获取当前的response 输出类型
     * @access protected
     * @return string
     */
    protected function getResponseType()
    {
        return 'json';
    }


}
```

* _checkPostData() 方法就是用来验证用户提交的数据和token 是否能通过验证的
加密方法: md5("post入参按照字母顺序递增拼接成字符串" . "不同的版本号对应的key")
#### 前端保存有我们的版本号和该版本号对应的key; 每次前端访问接口时需要将版本号传给我们,我们根据传递的版本号得到key, 知道使用哪个key进行加密。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【课程介绍】     课程目标:             - 有状态登录和无状态登录的区别             - 常见的非对称加密算法和非对称的加密方式             - 老版本只使用jwt进行加密的弊端             - 授权中心的授权流程             - 如何整合网关组件实现jwt安全验证             - 理解什么是公钥什么是私钥      - 深刻理解授权流程什么是有状态? 有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?- 服务端保存大量数据,增加服务端压力- 服务端保存用户状态,无法进行水平扩展- 客户端请求依赖服务端,多次请求必须访问同一台服务器。什么是无状态? 微服务集群中的每个服务,对外提供的都是Rest风格的接口。而Rest风格的一个最重要的规范就是:服务的无状态性,即:- 服务端不保存任何客户端请求者信息- 客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份带来的好处是什么呢?- 客户端请求不依赖服务端的信息,任何多次请求不需要必须访问到同一台服务- 服务端的集群和状态对客户端透明- 服务端可以任意的迁移和伸缩- 减小服务端存储压力
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值