SecurityController.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: NODELOG
  5. * Date: 16/7/26
  6. * Time: 下午4:02
  7. */
  8. namespace common\modules\user\frontend\controllers;
  9. use common\modules\user\models\Auth;
  10. use common\modules\user\models\LoginForm;
  11. use common\modules\user\models\PasswordResetRequestForm;
  12. use common\modules\user\models\ResetPasswordForm;
  13. use common\modules\user\models\User;
  14. use Yii;
  15. use yii\authclient\ClientInterface;
  16. use yii\base\InvalidParamException;
  17. use yii\filters\AccessControl;
  18. use yii\filters\VerbFilter;
  19. use yii\helpers\ArrayHelper;
  20. use yii\helpers\Url;
  21. use yii\web\BadRequestHttpException;
  22. use yii\web\Controller;
  23. class SecurityController extends Controller
  24. {
  25. public function behaviors()
  26. {
  27. return [
  28. 'access' => [
  29. 'class' => AccessControl::className(),
  30. 'only' => ['logout'],
  31. 'rules' => [
  32. [
  33. 'actions' => ['logout'],
  34. 'allow' => true,
  35. 'roles' => ['@'],
  36. ],
  37. ],
  38. ],
  39. 'verbs' => [
  40. 'class' => VerbFilter::className(),
  41. 'actions' => [
  42. 'logout' => ['post'],
  43. ],
  44. ],
  45. ];
  46. }
  47. public function actions()
  48. {
  49. return [
  50. 'auth' => [
  51. 'class' => 'yii\authclient\AuthAction',
  52. 'successCallback' => \Yii::$app->user->isGuest
  53. ? [$this, 'authenticate']
  54. : [$this, 'connect'],
  55. 'redirectView' => __DIR__ . '/redirect.php'
  56. ],
  57. ];
  58. }
  59. public function authenticate(ClientInterface $client)
  60. {
  61. $attributes = $client->getUserAttributes();
  62. $email = ArrayHelper::getValue($attributes, 'email');
  63. $id = ArrayHelper::getValue($attributes, 'id');
  64. $nickname = ArrayHelper::getValue($attributes, 'login');
  65. /** @var Auth $auth */
  66. $auth = Auth::find()->where([
  67. 'source' => $client->getId(),
  68. 'source_id' => $id,
  69. ])->one();
  70. if ($auth) { // login
  71. /** @var User $user */
  72. $user = $auth->user;
  73. Yii::$app->user->login($user);
  74. } else { // signup
  75. if ($email !== null && User::find()->where(['email' => $email])->exists()) {
  76. Yii::$app->getSession()->setFlash('error', [
  77. Yii::t('app', "User with the same email as in {client} account already exists but isn't linked to it. Login using email first to link it.", ['client' => $client->getTitle()]),
  78. ]);
  79. } else {
  80. $password = Yii::$app->security->generateRandomString(6);
  81. $user = new User([
  82. 'scenario' => 'create',
  83. 'username' => User::findByUsername($nickname) ? $nickname . '_' . mt_rand(1000, 9999) : $nickname,
  84. 'email' => $email,
  85. 'password' => $password,
  86. ]);
  87. $user->generateAuthKey();
  88. $user->generatePasswordResetToken();
  89. $transaction = User::getDb()->beginTransaction();
  90. if ($user->save()) {
  91. $auth = new Auth([
  92. 'user_id' => $user->id,
  93. 'source' => $client->getId(),
  94. 'source_id' => (string)$id,
  95. ]);
  96. if ($auth->save()) {
  97. $transaction->commit();
  98. Yii::$app->user->login($user);
  99. } else {
  100. Yii::$app->getSession()->setFlash('error', [
  101. Yii::t('app', 'Unable to save {client} account: {errors}', [
  102. 'client' => $client->getTitle(),
  103. 'errors' => json_encode($auth->getErrors()),
  104. ]),
  105. ]);
  106. }
  107. } else {
  108. Yii::$app->getSession()->setFlash('error', [
  109. Yii::t('app', 'Unable to save user: {errors}', [
  110. 'client' => $client->getTitle(),
  111. 'errors' => json_encode($user->getErrors()),
  112. ]),
  113. ]);
  114. }
  115. }
  116. }
  117. }
  118. public function connect(ClientInterface $client)
  119. {
  120. $attributes = $client->getUserAttributes();
  121. $id = ArrayHelper::getValue($attributes, 'id');
  122. /** @var Auth $auth */
  123. $auth = Auth::find()->where([
  124. 'source' => $client->getId(),
  125. 'source_id' => $id,
  126. ])->one();
  127. if (!$auth) { // add auth provider
  128. $auth = new Auth([
  129. 'user_id' => Yii::$app->user->id,
  130. 'source' => $client->getId(),
  131. 'source_id' => (string)$attributes['id'],
  132. ]);
  133. if ($auth->save()) {
  134. /** @var User $user */
  135. Yii::$app->getSession()->setFlash('success', [
  136. Yii::t('app', 'Linked {client} account.', [
  137. 'client' => $client->getTitle()
  138. ]),
  139. ]);
  140. } else {
  141. Yii::$app->getSession()->setFlash('error', [
  142. Yii::t('app', 'Unable to link {client} account: {errors}', [
  143. 'client' => $client->getTitle(),
  144. 'errors' => json_encode($auth->getErrors()),
  145. ]),
  146. ]);
  147. }
  148. } else { // there's existing auth
  149. Yii::$app->getSession()->setFlash('error', [
  150. Yii::t('app',
  151. 'Unable to link {client} account. There is another user using it.',
  152. ['client' => $client->getTitle()]),
  153. ]);
  154. }
  155. $this->action->successUrl = Url::to(['/user/settings/auth']);
  156. }
  157. /**
  158. * Logs in a user.
  159. *
  160. * @return mixed
  161. */
  162. public function actionLogin()
  163. {
  164. if (!\Yii::$app->user->isGuest) {
  165. return $this->goHome();
  166. }
  167. $model = new LoginForm();
  168. if ($model->load(Yii::$app->request->post()) && $model->login()) {
  169. if (Yii::$app->request->isAjax) {
  170. Yii::$app->response->format = 'json';
  171. return ['message' => '登录成功'];
  172. }
  173. return $this->goBack();
  174. } else {
  175. if (Yii::$app->request->isAjax) {
  176. return $this->renderAjax('login', [
  177. 'model' => $model,
  178. 'module' => $this->module
  179. ]);
  180. }
  181. return $this->render('login', [
  182. 'model' => $model,
  183. 'module' => $this->module
  184. ]);
  185. }
  186. }
  187. /**
  188. * Logs out the current user.
  189. *
  190. * @return mixed
  191. */
  192. public function actionLogout()
  193. {
  194. Yii::$app->user->logout();
  195. return $this->goHome();
  196. }
  197. /**
  198. * Requests password reset.
  199. *
  200. * @return mixed
  201. */
  202. public function actionRequestPasswordReset()
  203. {
  204. $model = new PasswordResetRequestForm();
  205. if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  206. if ($model->sendEmail()) {
  207. Yii::$app->session->setFlash('success', '请登录邮箱重置密码');
  208. return $this->goHome();
  209. } else {
  210. Yii::$app->session->setFlash('error', '很抱歉,发生错误了!');
  211. }
  212. }
  213. return $this->render('requestPasswordResetToken', [
  214. 'model' => $model,
  215. ]);
  216. }
  217. /**
  218. * Resets password.
  219. *
  220. * @param string $token
  221. *
  222. * @return mixed
  223. *
  224. * @throws BadRequestHttpException
  225. */
  226. public function actionResetPassword($token)
  227. {
  228. try {
  229. $model = new ResetPasswordForm($token);
  230. } catch (InvalidParamException $e) {
  231. throw new BadRequestHttpException($e->getMessage());
  232. }
  233. if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) {
  234. Yii::$app->session->setFlash('success', '新密码设置成功!');
  235. return $this->goHome();
  236. }
  237. return $this->render('resetPassword', [
  238. 'model' => $model,
  239. ]);
  240. }
  241. }