AuthController.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <?php
  2. /**
  3. * 描述.
  4. *
  5. * @author nj
  6. * @date 2021-05-18 20:38:13
  7. */
  8. namespace Modules\ManageApi\Controllers;
  9. use App\Repositories\ManagerRepository;
  10. use App\Repositories\Utils\JwtRepository;
  11. use Modules\ManageApi\Services\ManageAuthService;
  12. use Modules\ManageApi\Controllers\BaseController;
  13. use Validator;
  14. use App\Repositories\ManagerLogRepository;
  15. use Lcobucci\JWT\Token;
  16. use Otp\Otp;
  17. use Otp\GoogleAuthenticator;
  18. use ParagonIE\ConstantTime\Encoding;
  19. class AuthController extends BaseController
  20. {
  21. /**
  22. * Jwt受众.
  23. *
  24. * @var string
  25. */
  26. private $jwtAud = 'manage-users';
  27. /**
  28. * 属性描述.
  29. *
  30. * @var ManagerLogRepository
  31. */
  32. protected $logRepo = null;
  33. public function login()
  34. {
  35. $inputData = $this->getJsonData();
  36. /**
  37. * @var Validator $validatorFactory
  38. */
  39. $validatorFactory = app('validator');
  40. /**
  41. * @var ManagerRepository $managerRepo
  42. */
  43. $managerRepo = app(ManagerRepository::class);
  44. /**
  45. * @var ManageAuthService $authService
  46. */
  47. $authService = app(ManageAuthService::class);
  48. $rules = [
  49. 'account' => 'required|max:120',
  50. 'password' => 'required|max:64',
  51. 'verify' => 'nullable|max:12',
  52. 'ggcode' => 'nullable|max:10',
  53. ];
  54. $validator = $validatorFactory->make($inputData, $rules);
  55. if ($validator->fails()) {
  56. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  57. return json_fail($validator->errors()->first());
  58. }
  59. // 查询字段.
  60. $columns = [
  61. 'id', 'manager_uid', 'username', 'nick', 'role_id', 'password', 'salt', 'locked_at', 'otp_secret',
  62. ];
  63. // 条件.
  64. $conditions = ['username' => $inputData['account']];
  65. $managers = $managerRepo->findWhere($conditions, $columns);
  66. // 先判断是否存在用户.
  67. if ($managers->count() == 0) {
  68. $logSubject = '后台登陆获取token失败;原因:无此账号;入参:account['. $inputData['account'] .'];密码:['. pass_encode($inputData['password']) .']';
  69. $logSvalue = '';
  70. $logDbData = [];
  71. $this->log($logSubject, $logSvalue, $logDbData);
  72. // 给一个不容易分析的错误信息给前台.
  73. return json_fail('账号或者密码错误.');
  74. }
  75. // 取第一个用户.
  76. $manager = $managers->first();
  77. $md5password = $managerRepo->generatePassword($inputData['password'], $manager->salt);
  78. if ($manager->password !== $md5password) {
  79. $logSubject = '后台登陆获取token失败;原因:密码错误;入参:account['. $inputData['account'] .'];密码:['. pass_encode($inputData['password']) .']';
  80. $logSvalue = '';
  81. $logDbData = [];
  82. $this->log($logSubject, $logSvalue, $logDbData);
  83. return json_fail('账号或者密码错误.');
  84. }
  85. $ggcode = isset($inputData['ggcode']) ? $inputData['ggcode'] : '';
  86. $isOpenOtp = boolval(env('OTP_OPEN', true)); //是否开启谷歌身份码验证功能
  87. if ($isOpenOtp) {
  88. if (empty($ggcode)) {
  89. return json_fail('请填写身份码.');
  90. }
  91. $otp = new Otp();
  92. $otpSecret = !empty($manager->otp_secret) ? $manager->otp_secret : GoogleAuthenticator::generateRandom();
  93. $otpCheckResult = $otp->checkTotp(Encoding::base32DecodeUpper($otpSecret), $ggcode);
  94. if (!$otpCheckResult) {
  95. $logSubject = '后台登陆获取token失败;原因:OTP错误;入参:account['. $inputData['account'] .'];密码:['. pass_encode($inputData['password']) .'];otp:['. pass_encode($ggcode) .']';
  96. $logSvalue = '';
  97. $logDbData = [];
  98. $this->log($logSubject, $logSvalue, $logDbData);
  99. return json_fail('身份码不正确');
  100. }
  101. }
  102. if (!empty($manager->locked_at)) {
  103. $logSubject = '后台登陆获取token失败;原因:被锁定;入参:account['. $inputData['account'] .'];密码:['. pass_encode($inputData['password']) .']';
  104. $logSvalue = '';
  105. $logDbData = [];
  106. $this->log($logSubject, $logSvalue, $logDbData);
  107. return json_fail('您已经被锁定,无法登陆.');
  108. }
  109. $logSubject = '后台登录成功';
  110. $logSvalue = $manager->manager_uid;
  111. list($module, $action) = $this->getModuleAndAction();
  112. $inputs = [
  113. 'manager_uid' => $manager->manager_uid,
  114. 'username' => $manager->username,
  115. 'nick' => $manager->nick,
  116. 'subject' => mb_strcut($logSubject, 0, 700),
  117. 'module' => $module,
  118. 'action' => $action,
  119. 'svalue' => !empty($logSvalue) ? $logSvalue : '',
  120. 'db_data' => [],
  121. ];
  122. $this->getLogRepo()->createOne($inputs);
  123. $tokenInfo = $authService->createSingleJwt($manager->manager_uid, $manager->role_id);
  124. $data = [
  125. 'token' => $tokenInfo['token'],
  126. 'expired_at' => $tokenInfo['expired_at'],
  127. 'manager_uid' => $manager->manager_uid,
  128. ];
  129. return json_success($data);
  130. }
  131. public function logout()
  132. {
  133. }
  134. /**
  135. * 刷新Token并返回token.
  136. * @param mixed $validatorFactory
  137. * @param JwtRepository $jwtRepository
  138. * @param ManageAuthService $authService
  139. * @return mixed
  140. * @throws \Psr\SimpleCache\InvalidArgumentException
  141. */
  142. public function refreshToken() {
  143. /**
  144. * @var Validator $validatorFactory
  145. */
  146. $validatorFactory = app('validator');
  147. /**
  148. * @var ManagerRepository $managerRepo
  149. */
  150. $managerRepo = app(ManagerRepository::class);
  151. /**
  152. * @var ManageAuthService $authService
  153. */
  154. $authService = app(ManageAuthService::class);
  155. /**
  156. * @var JwtRepository $jwtRepository
  157. */
  158. $jwtRepository = app(JwtRepository::class);
  159. $inputData = $this->getJsonData();
  160. $rules = [
  161. 'manager_uid' => 'required',
  162. 'old_token' => 'required',
  163. ];
  164. $validator = $validatorFactory->make($inputData, $rules);
  165. if ($validator->fails()) {
  166. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  167. return json_fail($validator->errors()->first());
  168. }
  169. $validateResult = $jwtRepository->validateToken($inputData['old_token'], $this->jwtAud);
  170. if ($validateResult['is_illegal']) {
  171. return json_fail('无效数据传入.');
  172. }
  173. if (!$validateResult['is_valid']) {
  174. return json_fail('旧Token无效.');
  175. }
  176. /*if (!$validateResult['is_expired']) {
  177. // 旧token没过期
  178. return json_fail('旧token怎么了');
  179. }*/
  180. /**
  181. * @var Token $tokenObj
  182. */
  183. $tokenObj = $validateResult['token_obj'];
  184. $claims = $tokenObj->claims();
  185. $managerUid = $claims->get('manager_uid');
  186. $roleId = $claims->get('role_id');
  187. // 检查入参设备信息是否有效.
  188. if ($managerUid != $inputData['manager_uid']) {
  189. $logSubject = '后台登陆刷新token失败;原因:入参manager_uid和token中的manager_uid不一致;入参:manager_uid['. $inputData['manager_uid'] .']';
  190. $logSvalue = '';
  191. $logDbData = [];
  192. $this->log($logSubject, $logSvalue, $logDbData);
  193. return json_fail('无效数据匹配.');
  194. }
  195. $tokenInfo = $authService->createSingleJwt($managerUid, $roleId);
  196. $data = [
  197. 'token' => $tokenInfo['token'],
  198. 'expired_at' => $tokenInfo['expired_at'],
  199. ];
  200. return json_success($data);
  201. }
  202. /**
  203. * php ping
  204. * @return string
  205. */
  206. public function ping()
  207. {
  208. return 'pong';
  209. }
  210. /**
  211. * 记录操作日志.
  212. * @param string $subject 主题.
  213. * @param string $svalue 关联数据.
  214. * @param array $dbData 此数组数据结构一定要是["after_items" => [0, 1, 2], "before_items" => [0, 1, 2]], after_items,before_items 是一个二维码数组.
  215. * @return bool
  216. */
  217. protected function log(string $subject, $svalue = '', $dbData = [])
  218. {
  219. list($module, $action) = $this->getModuleAndAction();
  220. $inputs = [
  221. 'manager_uid' => '',
  222. 'username' => '',
  223. 'nick' => '匿名',
  224. 'subject' => mb_strcut((string)$subject, 0, 700),
  225. 'module' => $module,
  226. 'action' => $action,
  227. 'svalue' => !empty($svalue) ? mb_strcut((string)$svalue, 0, 700) : '',
  228. 'db_data' => $dbData,
  229. ];
  230. $this->getLogRepo()->createOne($inputs);
  231. return true;
  232. }
  233. /**
  234. * 获取日志仓库.
  235. * @return ManagerLogRepository|null
  236. */
  237. protected function getLogRepo()
  238. {
  239. if (empty($this->logRepo)) {
  240. $this->logRepo = make(ManagerLogRepository::class);
  241. }
  242. return $this->logRepo;
  243. }
  244. }