AccountService.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. namespace App\Services\Account;
  3. use App\Consts\ErrorConst;
  4. use App\Facade\Site;
  5. use App\Libs\AliSMS;
  6. use App\Libs\Utils;
  7. use Illuminate\Support\Facades\DB;
  8. use OSS\Core\OssException;
  9. use OSS\OssClient;
  10. class AccountService
  11. {
  12. private $salt = 'bXBfYXVkaW8=';
  13. public function __construct() {}
  14. /**
  15. * @param $account
  16. * @param $passwd
  17. * @return array
  18. */
  19. public function login($account, $passwd): array
  20. {
  21. // 密码
  22. $pwd = md5($passwd . $this->salt);
  23. $user = DB::table('mp_manage_users')->where('account', $account)->where('pwd', $pwd)->where('is_deleted', 0)->first();
  24. if (!$user) {
  25. Utils::throwError('20003:用户不存在');
  26. }
  27. if ((int)getProp($user, 'is_enabled') === 0) {
  28. Utils::throwError('20003:用户已被禁用');
  29. }
  30. // 更新 token、token 过期时间与 refresh_token
  31. $uid = getProp($user, 'id');
  32. $nickname = getProp($user, 'nickname');
  33. $token = (string)getProp($user, 'token');
  34. $refreshToken = (string)getProp($user, 'refresh_token');
  35. if (!config('token.expire_check_enabled')) {
  36. // 开关关闭:仅依据 token 是否存在处理,不写入 token 过期时间与 refresh_token 相关字段
  37. if ($token === '') {
  38. $token = md5(makeRandStr(32));
  39. DB::table('mp_manage_users')->where('id', $uid)->update([
  40. 'token' => $token,
  41. 'updated_at' => date('Y-m-d H:i:s'),
  42. ]);
  43. }
  44. $tokenData = $this->currentTokenData($user);
  45. $tokenData['token'] = $token;
  46. } elseif ($token !== '' && $refreshToken !== ''
  47. && !$this->isExpired(getProp($user, 'token_expires_at'))
  48. && !$this->isExpired(getProp($user, 'refresh_token_expires_at'))) {
  49. // 已有可用登录态:重新登录不刷新 token 信息(多人协作共用一个账号时避免互相踢下线)
  50. $tokenData = $this->currentTokenData($user);
  51. } else {
  52. // 首次登录、老用户只有 token 没有 refresh_token、登录态已过期:补齐 token 过期时间与 refresh_token 相关字段
  53. // token 未过期时沿用原 token,避免多人协作场景下其余人掉线
  54. $keepToken = $token !== '' && !$this->isExpired(getProp($user, 'token_expires_at')) ? $token : '';
  55. $tokenData = $this->buildTokenData($keepToken);
  56. DB::table('mp_manage_users')->where('id', $uid)->update([
  57. 'token' => $tokenData['token'],
  58. 'token_expires_at' => $tokenData['token_expires_at'],
  59. 'refresh_token' => $tokenData['refresh_token'],
  60. 'refresh_token_expires_at' => $tokenData['refresh_token_expires_at'],
  61. 'updated_at' => date('Y-m-d H:i:s'),
  62. ]);
  63. }
  64. // 用户角色
  65. $role = getProp($user, 'role');
  66. return array_merge(compact('uid', 'nickname', 'role'), $tokenData);
  67. }
  68. public function userInfo(): array
  69. {
  70. $uid = Site::getUid();
  71. $user = DB::table('mp_manage_users')->where('id', $uid)->where('is_deleted', 0)->first();
  72. if (!$user) {
  73. Utils::throwError('20003:用户不存在');
  74. }
  75. if ((int)getProp($user, 'is_enabled') === 0) {
  76. Utils::throwError('20003:用户已被禁用');
  77. }
  78. // 更新token
  79. $uid = getProp($user, 'id');
  80. $nickname = getProp($user, 'nickname');
  81. $token = getProp($user, 'token');
  82. $token_expires_at = getProp($user, 'token_expires_at');
  83. if ($token_expires_at) $token_expires_at = transDate($token_expires_at);
  84. $refresh_token = getProp($user, 'refresh_token');
  85. $refresh_token_expires_at = getProp($user, 'refresh_token_expires_at');
  86. if ($refresh_token_expires_at) $refresh_token_expires_at = transDate($refresh_token_expires_at);
  87. // 用户角色
  88. $role = getProp($user, 'role');
  89. $points = getProp($user, 'points');
  90. $avatar = getProp($user, 'avatar');
  91. return compact('uid', 'nickname', 'avatar', 'token', 'token_expires_at', 'refresh_token', 'refresh_token_expires_at', 'role', 'points');
  92. }
  93. /**
  94. * 通过 refresh_token 刷新 token 与 refresh_token
  95. *
  96. * @param string $refreshToken
  97. * @return array
  98. */
  99. public function refreshToken($refreshToken): array
  100. {
  101. $refreshToken = trim((string)$refreshToken);
  102. if ($refreshToken === '') {
  103. Utils::throwError('1003:请传入refresh_token');
  104. }
  105. $user = DB::table('mp_manage_users')->where('refresh_token', $refreshToken)->where('is_deleted', 0)->first();
  106. if (!$user) {
  107. Utils::throwError(ErrorConst::TOKEN_EXPIRED);
  108. }
  109. if ((int)getProp($user, 'is_enabled') === 0) {
  110. Utils::throwError('20003:用户已被禁用');
  111. }
  112. // refresh_token 自身过期则不可续期,需重新登录
  113. $refreshTokenExpiresAt = getProp($user, 'refresh_token_expires_at');
  114. if ($refreshTokenExpiresAt && strtotime($refreshTokenExpiresAt) <= time()) {
  115. Utils::throwError(ErrorConst::TOKEN_EXPIRED);
  116. }
  117. $uid = (int)getProp($user, 'id');
  118. $nickname = getProp($user, 'nickname');
  119. $role = getProp($user, 'role');
  120. // 刷新时强制更换 token 与 refresh_token
  121. $tokenData = $this->buildTokenData();
  122. DB::table('mp_manage_users')->where('id', $uid)->update([
  123. 'token' => $tokenData['token'],
  124. 'token_expires_at' => $tokenData['token_expires_at'],
  125. 'refresh_token' => $tokenData['refresh_token'],
  126. 'refresh_token_expires_at' => $tokenData['refresh_token_expires_at'],
  127. 'updated_at' => date('Y-m-d H:i:s'),
  128. ]);
  129. return array_merge(compact('uid', 'nickname', 'role'), $tokenData);
  130. }
  131. /**
  132. * 生成 token、refresh_token 及其过期时间
  133. *
  134. * @param string $token 需要沿用的 token(传空则重新生成)
  135. * @return array
  136. */
  137. private function buildTokenData(string $token = ''): array
  138. {
  139. if ($token === '') {
  140. $token = md5(makeRandStr(32));
  141. }
  142. return [
  143. 'token' => $token,
  144. 'token_expires_at' => date('Y-m-d H:i:s', time() + (int)config('token.expire_seconds', 864000)),
  145. 'refresh_token' => md5(makeRandStr(32)),
  146. 'refresh_token_expires_at' => date('Y-m-d H:i:s', time() + (int)config('token.refresh_expire_seconds', 2592000)),
  147. ];
  148. }
  149. /**
  150. * 读取当前登录态(不做任何刷新)
  151. *
  152. * @param object $user 用户记录
  153. * @return array
  154. */
  155. private function currentTokenData($user): array
  156. {
  157. return [
  158. 'token' => (string)getProp($user, 'token'),
  159. 'token_expires_at' => transDate(getProp($user, 'token_expires_at')),
  160. 'refresh_token' => (string)getProp($user, 'refresh_token'),
  161. 'refresh_token_expires_at' => transDate(getProp($user, 'refresh_token_expires_at')),
  162. ];
  163. }
  164. /**
  165. * 时间是否已过期(空值视为未过期,兼容历史数据)
  166. *
  167. * @param mixed $expiresAt
  168. * @return bool
  169. */
  170. private function isExpired($expiresAt): bool
  171. {
  172. return (bool)($expiresAt && strtotime($expiresAt) <= time());
  173. }
  174. /**
  175. * 退出登录
  176. *
  177. * @param $token
  178. * @return bool
  179. */
  180. public function logout($token): bool
  181. {
  182. if (empty($token)) {
  183. return true;
  184. }
  185. // 退出不影响多设备
  186. return DB::table('mp_manage_users')->where('token', $token)->update([
  187. 'updated_at' => date('Y-m-d H:i:s')
  188. ]);
  189. }
  190. }