AuthController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <?php
  2. namespace App\Http\Controllers\Passport;
  3. use App\Http\Controllers\Controller;
  4. use App\Http\Requests\Passport\AuthRegister;
  5. use App\Http\Requests\Passport\AuthForget;
  6. use App\Http\Requests\Passport\AuthLogin;
  7. use App\Jobs\SendEmailJob;
  8. use App\Services\AuthService;
  9. use Illuminate\Http\Request;
  10. use Illuminate\Support\Facades\Cache;
  11. use App\Models\Plan;
  12. use App\Models\User;
  13. use App\Models\InviteCode;
  14. use App\Utils\Helper;
  15. use App\Utils\Dict;
  16. use App\Utils\CacheKey;
  17. use ReCaptcha\ReCaptcha;
  18. use Firebase\JWT\JWT;
  19. class AuthController extends Controller
  20. {
  21. public function loginWithMailLink(Request $request)
  22. {
  23. if (!(int)config('v2board.login_with_mail_link_enable')) {
  24. abort(404);
  25. }
  26. $params = $request->validate([
  27. 'email' => 'required|email',
  28. 'redirect' => 'nullable'
  29. ]);
  30. if (Cache::get(CacheKey::get('LAST_SEND_LOGIN_WITH_MAIL_LINK_TIMESTAMP', $params['email']))) {
  31. abort(500, __('Sending frequently, please try again later'));
  32. }
  33. $user = User::where('email', $params['email'])->first();
  34. if (!$user) {
  35. return response([
  36. 'data' => true
  37. ]);
  38. }
  39. $code = Helper::guid();
  40. $key = CacheKey::get('TEMP_TOKEN', $code);
  41. Cache::put($key, $user->id, 300);
  42. Cache::put(CacheKey::get('LAST_SEND_LOGIN_WITH_MAIL_LINK_TIMESTAMP', $params['email']), time(), 60);
  43. $redirect = '/#/login?verify=' . $code . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
  44. if (config('v2board.app_url')) {
  45. $link = config('v2board.app_url') . $redirect;
  46. } else {
  47. $link = url($redirect);
  48. }
  49. SendEmailJob::dispatch([
  50. 'email' => $user->email,
  51. 'subject' => __('Login to :name', [
  52. 'name' => config('v2board.app_name', 'V2Board')
  53. ]),
  54. 'template_name' => 'login',
  55. 'template_value' => [
  56. 'name' => config('v2board.app_name', 'V2Board'),
  57. 'link' => $link,
  58. 'url' => config('v2board.app_url')
  59. ]
  60. ]);
  61. return response([
  62. 'data' => $link
  63. ]);
  64. }
  65. public function register(AuthRegister $request)
  66. {
  67. if ((int)config('v2board.register_limit_by_ip_enable', 0)) {
  68. $registerCountByIP = Cache::get(CacheKey::get('REGISTER_IP_RATE_LIMIT', $request->ip())) ?? 0;
  69. if ((int)$registerCountByIP >= (int)config('v2board.register_limit_count', 3)) {
  70. abort(500, __('Register frequently, please try again after :minute minute', [
  71. 'minute' => config('v2board.register_limit_expire', 60)
  72. ]));
  73. }
  74. }
  75. if ((int)config('v2board.recaptcha_enable', 0)) {
  76. $recaptcha = new ReCaptcha(config('v2board.recaptcha_key'));
  77. $recaptchaResp = $recaptcha->verify($request->input('recaptcha_data'));
  78. if (!$recaptchaResp->isSuccess()) {
  79. abort(500, __('Invalid code is incorrect'));
  80. }
  81. }
  82. if ((int)config('v2board.email_whitelist_enable', 0)) {
  83. if (!Helper::emailSuffixVerify(
  84. $request->input('email'),
  85. config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT))
  86. ) {
  87. abort(500, __('Email suffix is not in the Whitelist'));
  88. }
  89. }
  90. if ((int)config('v2board.email_gmail_limit_enable', 0)) {
  91. $prefix = explode('@', $request->input('email'))[0];
  92. if (strpos($prefix, '.') !== false || strpos($prefix, '+') !== false) {
  93. abort(500, __('Gmail alias is not supported'));
  94. }
  95. }
  96. if ((int)config('v2board.stop_register', 0)) {
  97. abort(500, __('Registration has closed'));
  98. }
  99. if ((int)config('v2board.invite_force', 0)) {
  100. if (empty($request->input('invite_code'))) {
  101. abort(500, __('You must use the invitation code to register'));
  102. }
  103. }
  104. if ((int)config('v2board.email_verify', 0)) {
  105. if (empty($request->input('email_code'))) {
  106. abort(500, __('Email verification code cannot be empty'));
  107. }
  108. if (Cache::get(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email'))) !== $request->input('email_code')) {
  109. abort(500, __('Incorrect email verification code'));
  110. }
  111. }
  112. $email = $request->input('email');
  113. $password = $request->input('password');
  114. $exist = User::where('email', $email)->first();
  115. if ($exist) {
  116. abort(500, __('Email already exists'));
  117. }
  118. $user = new User();
  119. $user->email = $email;
  120. $user->password = password_hash($password, PASSWORD_DEFAULT);
  121. $user->uuid = Helper::guid(true);
  122. $user->token = Helper::guid();
  123. if ($request->input('invite_code')) {
  124. $inviteCode = InviteCode::where('code', $request->input('invite_code'))
  125. ->where('status', 0)
  126. ->first();
  127. if (!$inviteCode) {
  128. if ((int)config('v2board.invite_force', 0)) {
  129. abort(500, __('Invalid invitation code'));
  130. }
  131. } else {
  132. $user->invite_user_id = $inviteCode->user_id ? $inviteCode->user_id : null;
  133. if (!(int)config('v2board.invite_never_expire', 0)) {
  134. $inviteCode->status = 1;
  135. $inviteCode->save();
  136. }
  137. }
  138. }
  139. // try out
  140. if ((int)config('v2board.try_out_plan_id', 0)) {
  141. $plan = Plan::find(config('v2board.try_out_plan_id'));
  142. if ($plan) {
  143. $user->transfer_enable = $plan->transfer_enable * 1073741824;
  144. $user->plan_id = $plan->id;
  145. $user->group_id = $plan->group_id;
  146. $user->expired_at = time() + (config('v2board.try_out_hour', 1) * 3600);
  147. }
  148. }
  149. if (!$user->save()) {
  150. abort(500, __('Register failed'));
  151. }
  152. if ((int)config('v2board.email_verify', 0)) {
  153. Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
  154. }
  155. $user->last_login_at = time();
  156. $user->save();
  157. if ((int)config('v2board.register_limit_by_ip_enable', 0)) {
  158. Cache::put(
  159. CacheKey::get('REGISTER_IP_RATE_LIMIT', $request->ip()),
  160. (int)$registerCountByIP + 1,
  161. (int)config('v2board.register_limit_expire', 60) * 60
  162. );
  163. }
  164. $authService = new AuthService($user);
  165. return response()->json([
  166. 'data' => $authService->generateAuthData('register')
  167. ]);
  168. }
  169. public function login(AuthLogin $request)
  170. {
  171. $email = $request->input('email');
  172. $password = $request->input('password');
  173. $passwordErrorCount = (int)Cache::get(CacheKey::get('PASSWORD_ERROR_LIMIT', $email), 0);
  174. if ($passwordErrorCount >= 5) {
  175. abort(500, __('There are too many password errors, please try again after 30 minutes.'));
  176. }
  177. $user = User::where('email', $email)->first();
  178. if (!$user) {
  179. abort(500, __('Incorrect email or password'));
  180. }
  181. if (!Helper::multiPasswordVerify(
  182. $user->password_algo,
  183. $user->password_salt,
  184. $password,
  185. $user->password)
  186. ) {
  187. Cache::put(
  188. CacheKey::get('PASSWORD_ERROR_LIMIT', $email),
  189. (int)$passwordErrorCount + 1,
  190. 30 * 60
  191. );
  192. abort(500, __('Incorrect email or password'));
  193. }
  194. if ($user->banned) {
  195. abort(500, __('Your account has been suspended'));
  196. }
  197. $authService = new AuthService($user);
  198. return response([
  199. 'data' => $authService->generateAuthData('login')
  200. ]);
  201. }
  202. public function token2Login(Request $request)
  203. {
  204. if ($request->input('token')) {
  205. $redirect = '/#/login?verify=' . $request->input('token') . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
  206. if (config('v2board.app_url')) {
  207. $location = config('v2board.app_url') . $redirect;
  208. } else {
  209. $location = url($redirect);
  210. }
  211. return redirect()->to($location)->send();
  212. }
  213. if ($request->input('verify')) {
  214. $key = CacheKey::get('TEMP_TOKEN', $request->input('verify'));
  215. $userId = Cache::get($key);
  216. if (!$userId) {
  217. abort(500, __('Token error'));
  218. }
  219. $user = User::find($userId);
  220. if (!$user) {
  221. abort(500, __('The user does not '));
  222. }
  223. if ($user->banned) {
  224. abort(500, __('Your account has been suspended'));
  225. }
  226. Cache::forget($key);
  227. $authService = new AuthService($user);
  228. return response([
  229. 'data' => $authService->generateAuthData('token')
  230. ]);
  231. }
  232. }
  233. public function getQuickLoginUrl(Request $request)
  234. {
  235. $authorization = $request->input('auth_data') ?? $request->header('authorization');
  236. if (!$authorization) abort(403, '未登录或登陆已过期');
  237. $user = AuthService::decryptAuthData($authorization);
  238. if (!$user) abort(403, '未登录或登陆已过期');
  239. $code = Helper::guid();
  240. $key = CacheKey::get('TEMP_TOKEN', $code);
  241. Cache::put($key, $user['id'], 60);
  242. $redirect = '/#/login?verify=' . $code . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
  243. if (config('v2board.app_url')) {
  244. $url = config('v2board.app_url') . $redirect;
  245. } else {
  246. $url = url($redirect);
  247. }
  248. return response([
  249. 'data' => $url
  250. ]);
  251. }
  252. public function forget(AuthForget $request)
  253. {
  254. if (Cache::get(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email'))) !== $request->input('email_code')) {
  255. abort(500, __('Incorrect email verification code'));
  256. }
  257. $user = User::where('email', $request->input('email'))->first();
  258. if (!$user) {
  259. abort(500, __('This email is not registered in the system'));
  260. }
  261. $user->password = password_hash($request->input('password'), PASSWORD_DEFAULT);
  262. $user->password_algo = NULL;
  263. $user->password_salt = NULL;
  264. if (!$user->save()) {
  265. abort(500, __('Reset failed'));
  266. }
  267. Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
  268. return response([
  269. 'data' => true
  270. ]);
  271. }
  272. }