工作中的"注册"流程以及代码备份
来源:互联网 发布:xss java 代码过滤 编辑:程序博客网 时间:2024/05/13 23:46
简要:
我觉得我们项目中用的注册流程好麻烦啊,可能是我是第一次给APP端写接口,token设计,存储,处理以及传输 都有好多啊,下面我将分步介绍.......
注意点: 两个token access_token 1 天 refresh_token 30 天 ,存储到redis, 采用string类型
流程:
- 注册用户时,判断手机号格式是否正确- 在没发送验证码之前, 判断手机号是否已经被注册过- 密码和确认密码判断是否一致- 新创建两个token setex access_token 1天setex refresh_token 30天- 注册完成后, 将两个token返回给用户, 并且默认用户是登录的设计格式:
- 生成的两个token组合方式:$accessToken = md5('at' . $mobile . $userId .time()); $refreshToken = md5('rt' . $mobile . $userId . time()); - 将两个token和user_id之间创建联系,然后存储到redis上,以后可以通过token获取对应的user_id user:at:{$access_token} => {$user_id} user:rt:{$refresh_token} => {$user_id}
说明: 当生成好两个token后, 将他们与user_id建立起来,然后我将两个token返回给APP端.
注册:代码如下:
/** * Action Register * 用户注册 */ public function actionRegister() { $params = Yii::$app->request->post(); $mAccount = new Account(); $util = Yii::$app->util; //规格: 由8-16位的数字,字母组成的密码,其中不能有空格,不能全是数字,不能全是字母 $regular = "/((?=.*\d)(?=.*\D)|(?=.*[a-zA-Z])(?=.*[^a-zA-Z]))^.{8,16}$/"; if (!$params) { return $util->formatResData(1101, '无参数提供', (object)[], false); } if (!isset($params['mobile']) || !$params['mobile']) { return $util->formatResData(1102, '手机号不能为空', (object)[], false); } if (!$util->regularMobile($params['mobile'])) { return $util->formatResData(1103, '手机号码格式不正确', (object)[], false); } if (!isset($params['vcode']) || !$params['vcode']) { return yii::$app->util->formatResData(1104, '验证码不能为空', (object)[], false); } if (!isset($params['password']) || !$params['password']) { return yii::$app->util->formatResData(1105, '密码不能为空', (object)[], false); } if (!isset($params['confirm_password']) || !$params['confirm_password']) { return yii::$app->util->formatResData(1106, '确认密码不能为空', (object)[], false); } $users = $mAccount->isExistMobile($params['mobile'], 'user_id, salt, status'); $status = 0; if ($users) { $status = $users['status']; //如果该用户存在,且状态为可用|禁用,都提示已注册 if (($status == Account::STATUS_ENABLE) || ($status == Account::STATUS_DISABLE)){ return $util->formatResData(1107, '该手机号已被注册', (object)[], false); } } //TODO 判断验证码是否正确 $mobie_white_list = array('手机号', '手机号1'); if(in_array($params['mobile'], $mobie_white_list)) { } else if (($result = $this->checkSmsVcode('reg', $params['mobile'], $params['vcode'])) !== true) { return $result; } $mInviteCode = new Invitecode(); //判断邀请码是否存在 if (isset($params['code']) && $params['code']) { $isBindMobile = $mInviteCode->isBindMobile($params['code'], $params['mobile']); if (!$isBindMobile) { return $util->formatResData(1108, '该手机号与邀请码未绑定', (object)[], false); } $data['is_receive_invokecode'] = HmcUser::STATUS_INVOKECODE_RECEIVED; } $tmp = $this->judgePassword($params['password'], $params['confirm_password'], $regular); if ($tmp) { return $tmp; } //从redis中获取用户ID $data = $this->getUid(); if (!isset($data['user_id']) || !$data['user_id']) { return $data; } $params['user_id'] = $data['user_id']; unset($params['confirm_password'], $params['vcode'], $params['code']); $mHmcUser = new HmcUser(); if (!$status) { $result = $mAccount->add($params); } else { $params['user_id'] = $users['user_id']; $updateVal['salt'] = $util->random(6); $updateVal['password'] = md5(md5($params['password']).$updateVal['salt']); $updateVal['status'] = Account::STATUS_ENABLE; $result = $mAccount->renew($params['mobile'], $updateVal); } if ($result) { $data['user_id'] = $params['user_id']; $data['mobile'] = $params['mobile']; if (!$status) { $userDetail = $mHmcUser->add($data); } //创建token,并将token存储在redis $handleData = $this->handleSession($params["user_id"], $params["mobile"]); if (!isset($handleData['variable']) || !$handleData['variable']) { return $handleData['error']; } $session = $handleData['variable']; Yii::$app->api->account_import((string)$params["user_id"], (string)$params["user_id"], ''); try { $smsData = ['mobile'=> $params['mobile'], 'business_type' => 'reg']; $result = $this->renewSmsUseage($smsData); } catch (\Exception $e) { //TODO 将短信使用情况出现错误的地方写到日志里面 } return $util->formatResData(0, '注册成功', $session, false); } else { return $util->formatResData(1201, '注册失败', (object)[], false); } }
刷新refresh_token步骤
流程如图所示:
代码如下:
/** * Action RefreshToken * 刷新refresh_token */ public function actionRefreshToken() { $params = Yii::$app->request->get(); if (!isset($params['refresh_token']) || !$params['refresh_token']) { return yii::$app->util->formatResData(1101, '未传递refresh_token参数', (object)[], false); } Yii::info($params['refresh_token'], 'api\refreshtoken'); $cache = Yii::$app->cache->instance('base'); $rtCountKey = 'user:rtcount:' . $params['refresh_token']; $unitMseconds = 500000; $count = $cache->incr($rtCountKey); $cache->expire($rtCountKey, 10); if ($count > 1 && $count <= 10) { // usleep($unitMseconds * $count); usleep($unitMseconds); } try { $tokenKey = "user:rt:" . $params['refresh_token']; $tmp = $cache->get($tokenKey); //判断refresh_token是否过期 if (!$tmp) { $tokens = $cache->exists('user:oldrt:' . $params['refresh_token']); if (!$tokens) { return yii::$app->util->formatResData(1102, 'refresh_token过期', (object)[], false); } else { $tokensKey = 'user:oldrt:' . $params['refresh_token']; $session['user_id'] = $cache->hget($tokensKey, 'user_id'); $session['access_token'] = $cache->hget($tokensKey, 'access_token'); $session['refresh_token'] = $cache->hget($tokensKey, 'refresh_token'); $session['sig'] = $cache->hget($tokensKey, 'sig'); } } else { //如果不过期,user:rt:refresh_token 获取对应的用户ID,然后先删除rt,再重新创建两个token $userId = $tmp; $cache->del($tokenKey); $mAccount = new Account(); $users = $mAccount->getByUid($userId, 'mobile'); //重新创建两个token $handleData = $this->handleSession($userId, $users['mobile']); //创建旧的refresh_token,与新的refresh_token之间关联的数据,防止并发导致找不到已经删过的refresh_token, 10s if (!isset($handleData['variable']) || !$handleData['variable']) { return $handleData['error']; } $session = $handleData['variable']; $accessToken = $session['access_token']; $refreshToken = $session['refresh_token']; $tmpTokenKey = "user:oldrt"; $oldRefreshToken = $params['refresh_token']; $sig = Yii::$app->sig->getSig($userId); $cache->hmset('user:oldrt:' . $oldRefreshToken, 'access_token', $accessToken, 'refresh_token', $refreshToken, 'user_id', $userId, 'sig', $sig); $cache->expire('user:oldrt:' . $oldRefreshToken, 60); } return yii::$app->util->formatResData(0, 'refresh_token刷新成功', $session, false); } catch (\Exception $e) { return yii::$app->util->formatResData(-1, '服务器连接失败,请稍后重试', (object)[], false); } }
里面涉及的方法:
1: 创建token方法 handleSession
/** * 创建token,并将token存储在redis上 * * @param string $userId 用户ID * @param string $mobile 手机号 * @param int $atTime access_token保存时间 * @param int $rtTime refresh_token保存时间 * * @return array * 说明: 返回的值: access_token,refresh_token,user_id,sig */ // protected function handleSession($userId, $mobile, $atTime = 300, $rtTime = 2592000) // protected function handleSession($userId, $mobile, $atTime = 120, $rtTime = 2592000) protected function handleSession($userId, $mobile, $atTime = 86400, $rtTime = 2592000) { $now = time(); $accessToken = md5('at' . $mobile . $userId . $now); $refreshToken = md5('rt' . $mobile . $userId . $now); $token = ['access_token' => $accessToken, 'refresh_token' => $refreshToken]; try { // FIXED: 设置过期时间设置的为经过多少秒过去而不是时间点,如果是时间点应该单独使用expireat $cache = Yii::$app->cache->instance('base'); $cache->setex('user:at:' . $accessToken, $atTime, $userId); $cache->setex('user:rt:' . $refreshToken, $rtTime, $userId); $sig = Yii::$app->sig->getSig($userId); $result['variable'] = [ 'access_token' => $accessToken, 'refresh_token' => $refreshToken, 'user_id' => $userId, 'sig' => $sig ]; } catch (\Exception $e) { $result['error'] = yii::$app->util->formatResData(-100, '连接redis服务器失败,请稍后重试 ', (object)[], false); } return $result; }
2:验证手机号格式方法: regularMobile()
/** * 中国移动 */ const CHINA_MOBILE_EXPR = '/^134[0-8]\d{7}$|^(?:13[5-9]|147|15[0-27-9]|178|18[2-478])\d{8}$/'; /** * 中国联通 */ const CHINA_UNION_EXPR = '/^(?:13[0-2]|145|15[56]|176|18[56])\d{8}$/'; /** * 中国电信 */ const CHINA_TELCOM_EXPR = '/^(?:133|153|177|18[019])\d{8}$/'; /** * 手机正则表达式验证 * * @param string $mobile 手机 * @return int false 表示验证失败 true表示成功 */ public function regularMobile($mobile) { return preg_match(self::CHINA_MOBILE_EXPR, $mobile) || preg_match(self::CHINA_UNION_EXPR, $mobile) || preg_match(self::CHINA_TELCOM_EXPR, $mobile) || preg_match(self::CHINA_OTHER_EXPR, $mobile); }3: 判断密码和确认密码 judgePassword()
/** * 判断密码和确认密码 */ public function judgePassword($password, $confirmPwd, $regular) { if (!preg_match($regular, $password)) { return yii::$app->util->formatResData(1401, '密码格式不正确', (object)[], false); } if (!preg_match($regular, $confirmPwd)) { return yii::$app->util->formatResData(1402, '确认密码格式不正确', (object)[], false); } if ($password !== $confirmPwd) { return yii::$app->util->formatResData(1403, '密码与确认密码不一致', (object)[], false); } }
* 为什么要创建两个token ?
- 假如你只设置一个token表示app端用户的登录状态, 那么如果你的token被别人采用非正当手段截取了, 他是不是就可以"为所欲为"了, 而我们设计两个token, access_token设置1天, refresh_token设置30天,
如果access_token过期了, refresh_token会刷新重新创建新的两个token, 并且把旧的refresh_token删掉. 由于access_token生存时间短暂, 那么假如被人盗取了, 没关系, 我们access_token过期后, 会用refresh_token刷新, 再重新创建新的两个token, 即便是refresh_token被盗取了, 也没关系, 因为又重新创建两个新的access_token和refresh_token, 你说这样是不是就比较完美了!
总结:
我只是把部分的流程列了出来,以后要是再碰到类似的,我就可以直接使用了,对于我来说,现在该学会的就是能够拿别人的代码应用到我的应用中,即便是我没明白,但是功能实现是第一步,因为工作领导不管你怎么样,人家要的是结果,因为现实的社会很残酷,不管你是谁,你是女生还是男生。
所以加油,我可以的,不能被别人看不起!
- 工作中的"注册"流程以及代码备份
- 工作中的登录流程以及代码备份
- Java 中的 JVM 工作原理以及流程
- mediarecorder中的方法以及工作流程的过程
- mediarecorder中的方法以及工作流程的过程
- Android之mediarecorder中的方法以及工作流程的过程
- MVC以及Struts2工作流程
- Filter(过滤器)以及工作流程
- jsp中的注册代码
- struts1.2工作原理以及工作流程
- mysqldump,mydumper以及xtrabackup备份流程简述
- 软件行业工作中的一些工作流程
- Openfire注册流程代码分析(转)
- 工作中的代码统计
- Struts2 之入门以及工作流程
- Struts2的工作流程以及原理
- bufferevent_write以及bufferevent工作流程探究
- git&repo常见命令以及工作流程
- Java多线程中Sleep与Wait的区别
- LeetCode 36 Valid Sudoku My Submissions Question
- 整理request ,response ,会话session ,全局application
- Leetcode Remove Duplicates from Sorted Array I and II
- 大括弧之战 代码风格
- 工作中的"注册"流程以及代码备份
- 心得:android开发网络层
- convert sorted array to binary search tree
- SlidingDrawer引发java.lang.IllegalArgumentException: The content attribute is must refer to an existin
- hdu 1016 Prime Ring Problem(dfs)
- 【poj 1416】Shredding Company 中文题意&题解&代码(C++)
- MySQL允许远程访问的设置
- 多线程 概念
- 怎么退出VI编辑模式