* @date 2020-01-22 20:24:20 */ declare (strict_types=1); namespace Modules\Manage\Controllers; use App\Controller\CoreController; use App\Model\ManagerModel; use App\Repositories\ManagerLogRepository; use App\Repositories\ManagerRepository; use App\Repositories\Utils\AccessControllerListsRepository; use App\Repositories\Utils\JwtRepository; use Hyperf\Validation\Contract\ValidatorFactoryInterface; use Modules\Manage\Services\AuthService; class AuthController extends CoreController { use \Hyperf\Di\Aop\ProxyTrait; use \Hyperf\Di\Aop\PropertyHandlerTrait; function __construct() { if (method_exists(parent::class, '__construct')) { parent::__construct(...func_get_args()); } $this->__handlePropertyHandler(__CLASS__); } /** * Jwt受众. * * @var string */ private $jwtAud = 'manage-users'; /** * 属性描述. * * @var ManagerLogRepository */ protected $logRepo = null; /** * 管理员登陆. * @param ValidatorFactoryInterface $validatorFactory * @param ManagerRepository $managerRepository * @param AuthService $authService * @return mixed * @throws \Psr\SimpleCache\InvalidArgumentException */ public function login(ValidatorFactoryInterface $validatorFactory, ManagerRepository $managerRepository, AuthService $authService) { $inputData = $this->getJsonData(); $rules = ['account' => 'required|max:120', 'password' => 'required|max:64', 'verify' => 'nullable|max:12']; $validator = $validatorFactory->make($inputData, $rules); if ($validator->fails()) { // 如果有错误(可能是多个信息),这里只取第一个错误信息返回. return json_fail($validator->errors()->first()); } // 查询字段. $columns = ['id', 'manager_id', 'username', 'nick', 'role_id', 'password', 'salt', 'locked_at']; // 条件. $conditions = ['username' => $inputData['account']]; $managers = make(ManagerRepository::class)->findWhere($conditions, $columns); // 先判断是否存在用户. if (!$managers->count()) { $logSubject = '后台登陆获取token失败;原因:无此账号;入参:account[' . $inputData['account'] . '];密码:[' . pass_encode($inputData['password']) . ']'; $logSvalue = ''; $logDbData = []; $this->log($logSubject, $logSvalue, $logDbData); // 给一个不容易分析的错误信息给前台. return json_fail('账号或者密码错误.'); } // 取第一个用户. $manager = $managers->first(); $md5password = make(ManagerRepository::class)->generatePassword($inputData['password'], $manager->salt); var_dump($md5password); if ($manager->password !== $md5password) { $logSubject = '后台登陆获取token失败;原因:密码错误;入参:account[' . $inputData['account'] . '];密码:[' . pass_encode($inputData['password']) . ']'; $logSvalue = ''; $logDbData = []; $this->log($logSubject, $logSvalue, $logDbData); return json_fail('账号或者密码错误.'); } if (!empty($manager->locked_at)) { $logSubject = '后台登陆获取token失败;原因:被锁定;入参:account[' . $inputData['account'] . '];密码:[' . pass_encode($inputData['password']) . ']'; $logSvalue = ''; $logDbData = []; $this->log($logSubject, $logSvalue, $logDbData); return json_fail('您已经被锁定,无法登陆.'); } $logSubject = '后台登录成功'; $logSvalue = $manager->manager_id; list($module, $action) = $this->getModuleAndAction(); $inputs = ['manager_id' => $manager->manager_id, 'username' => $manager->username, 'nick' => $manager->nick, 'subject' => mb_strcut($logSubject, 0, 700), 'module' => $module, 'action' => $action, 'svalue' => !empty($logSvalue) ? $logSvalue : '', 'db_data' => []]; $this->getLogRepo()->createOne($inputs); $tokenInfo = $authService->createSingleJwt($manager->manager_id, $manager->role_id); $data = ['token' => $tokenInfo['token'], 'expired_at' => $tokenInfo['expired_at'], 'manager_id' => $manager->manager_id]; return json_success($data); } public function logout() { } /** * 刷新Token并返回token. * @param ValidatorFactoryInterface $validatorFactory * @param JwtRepository $jwtRepository * @param \Modules\Manage\Services\AuthService $authService * @return mixed * @throws \Psr\SimpleCache\InvalidArgumentException */ public function refreshToken(ValidatorFactoryInterface $validatorFactory, JwtRepository $jwtRepository, AuthService $authService) { $inputData = $this->getJsonData(); $rules = ['manager_id' => 'required', 'old_token' => 'required']; $validator = $validatorFactory->make($inputData, $rules); if ($validator->fails()) { // 如果有错误(可能是多个信息),这里只取第一个错误信息返回. return json_fail($validator->errors()->first()); } $validateResult = $jwtRepository->validateToken($inputData['old_token'], $this->jwtAud); $tokenObj = $validateResult['token_obj']; $manager = new \stdClass(); $managerId = $tokenObj->getClaim('manager_id'); $roleId = $tokenObj->getClaim('role_id'); // 检查入参设备信息是否有效. if ($managerId != $inputData['manager_id']) { $logSubject = '后台登陆刷新token失败;原因:入参manager_id和token中的manager_id不一致;入参:manager_id[' . $inputData['manager_id'] . ']'; $logSvalue = ''; $logDbData = []; $this->log($logSubject, $logSvalue, $logDbData); return json_fail('无效数据匹配.'); } if (!$validateResult['is_valid'] && $validateResult['is_expired']) { return json_fail('旧Token无效'); } $tokenInfo = $authService->createSingleJwt($managerId, $roleId); $data = ['token' => $tokenInfo['token'], 'expired_at' => $tokenInfo['expired_at']]; return json_success($data); } /** * 记录操作日志. * @param string $subject 主题. * @param string $svalue 关联数据. * @param array $dbData 此数组数据结构一定要是["after_items" => [0, 1, 2], "before_items" => [0, 1, 2]], after_items,before_items 是一个二维码数组. * @return bool */ protected function log(string $subject, $svalue = '', $dbData = []) { list($module, $action) = $this->getModuleAndAction(); $inputs = ['manager_id' => '', 'username' => '', 'nick' => '匿名', 'subject' => mb_strcut((string) $subject, 0, 700), 'module' => $module, 'action' => $action, 'svalue' => !empty($svalue) ? mb_strcut((string) $svalue, 0, 700) : '', 'db_data' => $dbData]; $this->getLogRepo()->createOne($inputs); return true; } /** * 获取日志仓库. * @return ManagerLogRepository|null */ protected function getLogRepo() { if (empty($this->logRepo)) { $this->logRepo = make(ManagerLogRepository::class); } return $this->logRepo; } }