AuthController.php 9.3 KB

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