model = new Member(); } /** * 会员注册 * @param $data */ public function register($data) { //检测设置是否自动注册 //自动注册检测授权信息 //注册登录 } /** * 登录操作 * @param Member $member_info * @param string $login_type * @return array */ public function login(Member $member_info, string $login_type) { //绑定第三方授权 $this->bingOpenid($member_info); if (!$member_info->status) throw new ApiException('MEMBER_LOCK'); $member_info->login_time = time(); $member_info->login_ip = $this->request->ip(); $member_info->login_channel = $this->channel; $member_info->login_type = $login_type; $member_info->login_count++; $member_info->last_visit_time = time(); $member_info->save(); $token_info = $this->createToken($member_info); event("MemberLogin", $member_info); return [ 'token' => $token_info['token'], 'expires_time' => $token_info['params']['exp'], 'mobile' => $member_info->mobile ]; } /** * 账号登录 * @param string $username * @param string $password * @return array|false */ public function account(string $username, string $password) { $member_service = new MemberService(); $member_info = $member_service->findMemberInfo(['username|mobile' => $username]); if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在 if (!check_password($password, $member_info->password)) return false;//密码与账号不匹配 return $this->login($member_info, MemberLoginTypeDict::USERNAME); } /** * 手机号登录 * @param array $params * @return array */ public function mobile($params) { //校验手机验证码 $this->checkMobileCode($params['mobile']); //登录注册配置 $config = (new MemberConfigService())->getLoginConfig(); $is_mobile = $config['is_mobile']; $is_bind_mobile = $config['is_bind_mobile']; if ($is_mobile != 1 && $is_bind_mobile != 1) throw new AuthException('MOBILE_LOGIN_UNOPENED'); $member_service = new MemberService(); $member_info = $member_service->findMemberInfo(['mobile' => $params['mobile']]); if ($member_info->isEmpty()) { //开启强制绑定手机号,登录会自动注册并绑定手机号 if ($is_bind_mobile == 1) { $data = array( 'mobile' => $params['mobile'], 'nickname' => $params['nickname'], 'headimg' => $params['headimg'] ); return (new RegisterService())->register($params['mobile'], $data, MemberRegisterTypeDict::MOBILE, false); } else { throw new AuthException('MEMBER_NOT_EXIST');//账号不存在 } } return $this->login($member_info, MemberLoginTypeDict::MOBILE); } /** * 生成token * @param $member_info * @return array|null */ public function createToken($member_info): ?array { $expire_time = env('system.api_token_expire_time') ?? 3600;//todo 不一定和管理端合用这个token时限 return TokenAuth::createToken($member_info->member_id, AppTypeDict::API, ['member_id' => $member_info->member_id, 'username' => $member_info->username], $expire_time); } /** * 登陆退出(当前账户) */ public function logout(): ?bool { self::clearToken($this->member_id, $this->request->apiToken()); return true; } /** * 清理token * @param int $member_id * @param string|null $token * @return bool|null */ public static function clearToken(int $member_id, ?string $token = ''): ?bool { TokenAuth::clearToken($member_id, AppTypeDict::API, $token); return true; } /** * 解析客户端token * @param string|null $token * @return array */ public function parseToken(?string $token) { if (empty($token)) { //定义专属于授权认证机制的错误响应, 定义专属语言包 throw new AuthException('MUST_LOGIN', 401); } try { $token_info = TokenAuth::parseToken($token, AppTypeDict::API); } catch (Throwable $e) { // if(env('app_debug', false)){ // throw new AuthException($e->getMessage(), 401); // }else{ throw new AuthException('LOGIN_EXPIRE', 401); // } } if (!$token_info) { throw new AuthException('MUST_LOGIN', 401); } //验证有效次数或过期时间 return $token_info; } /** * 解析员工端token * @param string|null $token * @return array */ public function parsePersonnelToken(?string $token) { if (empty($token)) { //定义专属于授权认证机制的错误响应, 定义专属语言包 throw new AuthException('MUST_LOGIN', 401); } try { $token_info = TokenAuth::parseToken($token, AppTypeDict::PERSONNEL); } catch (Throwable $e) { // if(env('app_debug', false)){ // throw new AuthException($e->getMessage(), 401); // }else{ throw new AuthException('LOGIN_EXPIRE', 401); // } } if (!$token_info) { throw new AuthException('MUST_LOGIN', 401); } //验证有效次数或过期时间 return $token_info; } /** * 手机发送验证码 * @param $mobile * @param string $type 发送短信的业务场景 * @return array * @throws Exception */ public function sendMobileCode($mobile, string $type = '') { (new CaptchaService())->check(); if (empty($mobile)) throw new AuthException('MOBILE_NEEDED'); //发送 if (!in_array($type, SmsDict::SCENE_TYPE)) throw new AuthException('MEMBER_MOBILE_CAPTCHA_ERROR'); $code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);// 生成4位随机数,左侧补0 (new NoticeService())->send('member_verify_code', ['code' => $code, 'mobile' => $mobile]); //将验证码存入缓存 $key = md5(uniqid('', true)); $cache_tag_name = "mobile_key" . $mobile . $type; $this->clearMobileCode($mobile, $type); Cache::tag($cache_tag_name)->set($key, ['mobile' => $mobile, 'code' => $code, 'type' => $type], 600); return ['key' => $key]; } public function getMobileCodeCacheName() { } public function clearMobileCode($mobile, $type) { $cache_tag_name = "mobile_key" . $mobile . $type; Cache::tag($cache_tag_name)->clear(); } /** * 校验手机验证码 * @param string $mobile * @return true */ public function checkMobileCode(string $mobile) { if (empty($mobile)) throw new AuthException('MOBILE_NEEDED'); $mobile_key = request()->param('mobile_key', ''); $mobile_code = request()->param('mobile_code', ''); if (empty($mobile_key) || empty($mobile_code)) throw new AuthException('MOBILE_CAPTCHA_ERROR'); $cache = Cache::get($mobile_key); if (empty($cache)) throw new AuthException('MOBILE_CAPTCHA_ERROR'); $temp_mobile = $cache['mobile']; $temp_code = $cache['code']; $temp_type = $cache['type']; if ($temp_mobile != $mobile || $temp_code != $mobile_code) throw new AuthException('MOBILE_CAPTCHA_ERROR'); $this->clearMobileCode($temp_mobile, $temp_type); return true; } /** * 绑定openid * @param $member * @return true */ public function bingOpenid($member) { $open_id = $this->request->param('openid'); if (!empty($open_id)) { Log::write('channel_1' . $this->channel); if (!empty($this->channel)) { $openid_field = match ($this->channel) { 'wechat' => 'wx_openid', 'weapp' => 'weapp_openid', default => '' }; if (!empty($openid_field)) { if (!$member->isEmpty()) { if (empty($member->$openid_field)) { //todo 定义当前第三方授权方没有退出登录功能,故这儿不做openid是否存在账号验证 // $member_service = new MemberService(); // $open_member = $member_service->findMemberInfo([$openid_field => $open_id]); $member->$openid_field = $open_id; $member->save(); } else { if ($member->$openid_field != $open_id) { throw new AuthException('MEMBER_IS_BIND_AUTH'); } } } } } } return true; } /** * 重置密码 * @param string $mobile * @param string $password */ public function resetPassword(string $mobile, string $password) { $member_service = new MemberService(); //校验手机验证码 $this->checkMobileCode($mobile); $member_info = $member_service->findMemberInfo(['mobile' => $mobile]); if ($member_info->isEmpty()) throw new AuthException('MOBILE_NOT_EXIST_MEMBER');//账号不存在 //todo 需要考虑一下,新的密码和原密码一样能否通过验证 $password_hash = create_password($password); $data = array( 'password' => $password_hash, ); $member_service->editByFind($member_info, $data); self::clearToken($member_info['member_id'], $this->request->apiToken()); return true; } public function loginScanCode() { } public function loginByScanCode() { } public function checkScanCode() { } //员工登陆 public function loginByPersonnel($params) { //查询员工信息 $member_info = (new Personnel())->where('phone', $params['phone'])->find(); if(!$member_info){ throw new ApiException('账号不存在'); } if ($member_info->status != 2) throw new ApiException('账号状态异常禁止登录'); $user = (new SysUser())->where('username', $params['phone'])->find(); //create_password($params['password'])//创建密码 if (!check_password($params['password'], $user->password)) throw new ApiException('账号或密码错误'); $user->login_time = time(); $user->last_ip = $this->request->ip(); $user->login_type = 'mini'; $user->login_count++; $user->last_time = time(); $user->save(); $expire_time = env('system.api_token_expire_time') ?? 3600; //生成token $token_info = TokenAuth::createToken($member_info->id, AppTypeDict::PERSONNEL, ['id' => $member_info->id, 'member_id'=>$member_info->id, 'phone' => $member_info->phone, 'user_type' => $params['login_type']], $expire_time); // $depts = (new CampusPersonRole())->where('person_id', $member_info->id)->column('dept_id'); $user_type = CampusPersonRole::where('person_id', $member_info->id)-> $event = event("PersonnelLogin", $member_info); dd($event); return [ 'token' => $token_info['token'],//token 'expires_time' => $token_info['params']['exp'],//过期时间 'user_type' => $user_type//用户类型 ]; } }