Add user email verification
This commit is contained in:
parent
84f29de969
commit
ebcc693ab4
|
|
@ -274,6 +274,25 @@ class AuthController extends Controller
|
|||
return json(trans('auth.reset.success'), 0);
|
||||
}
|
||||
|
||||
public function verify(Request $request, UserRepository $users)
|
||||
{
|
||||
// Get user instance from repository
|
||||
$user = $users->get($request->get('uid'));
|
||||
|
||||
if (! $user || $user->verified) {
|
||||
throw new PrettyPageException(trans('auth.verify.invalid'), 1);
|
||||
}
|
||||
|
||||
if ($user->verification_token != $request->get('token')) {
|
||||
throw new PrettyPageException(trans('auth.verify.expired'), 1);
|
||||
}
|
||||
|
||||
$user->verified = true;
|
||||
$user->save();
|
||||
|
||||
return view('auth.verify');
|
||||
}
|
||||
|
||||
public function captcha()
|
||||
{
|
||||
$builder = new \Gregwar\Captcha\CaptchaBuilder;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use Mail;
|
||||
use View;
|
||||
use Utils;
|
||||
use Session;
|
||||
use App\Models\User;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -24,6 +26,9 @@ class UserController extends Controller
|
|||
public function __construct(UserRepository $users)
|
||||
{
|
||||
$this->user = $users->get(session('uid'));
|
||||
|
||||
// Send email verification link to new users
|
||||
$this->user->verification_token || $this->sendVerificationEmail();
|
||||
}
|
||||
|
||||
public function index()
|
||||
|
|
@ -94,6 +99,49 @@ class UserController extends Controller
|
|||
return $hours > 1 ? round($hours) : $hours;
|
||||
}
|
||||
|
||||
public function sendVerificationEmail()
|
||||
{
|
||||
// Rate limit of 60s
|
||||
$remain = 60 + session('last_mail_time', 0) - time();
|
||||
|
||||
if ($remain > 0) {
|
||||
return json(trans('user.verification.frequent-mail', compact('remain')), 1);
|
||||
}
|
||||
|
||||
if ($this->user->verified) {
|
||||
return json(trans('user.verification.verified'), 1);
|
||||
}
|
||||
|
||||
$key = config('app.key');
|
||||
$key = starts_with($key, 'base64:') ? base64_decode(substr($key, 7)) : $key;
|
||||
|
||||
$token = hash_hmac('sha256', str_random(40), $key);
|
||||
|
||||
$this->user->verification_token = $token;
|
||||
$this->user->save();
|
||||
|
||||
$email = $this->user->email;
|
||||
$url = option('site_url')."/auth/verify?uid={$this->user->uid}&token=$token";
|
||||
|
||||
try {
|
||||
Mail::send('mails.email-verification', compact('url'), function ($m) use ($email) {
|
||||
$site_name = option_localized('site_name');
|
||||
|
||||
$m->from(config('mail.username'), $site_name);
|
||||
$m->to($email)->subject(trans('user.verification.mail.title', ['sitename' => $site_name]));
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
// Write the exception to log
|
||||
report($e);
|
||||
|
||||
return json(trans('user.verification.failed', ['msg' => $e->getMessage()]), 2);
|
||||
}
|
||||
|
||||
Session::put('last_mail_time', time());
|
||||
|
||||
return json(trans('user.verification.success'), 0);
|
||||
}
|
||||
|
||||
public function profile()
|
||||
{
|
||||
return view('user.profile')->with('user', $this->user);
|
||||
|
|
|
|||
|
|
@ -44,10 +44,11 @@ class Kernel extends HttpKernel
|
|||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\CheckAuthenticated::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'admin' => \App\Http\Middleware\CheckAdministrator::class,
|
||||
'player' => \App\Http\Middleware\CheckPlayerExist::class,
|
||||
'setup' => \App\Http\Middleware\CheckInstallation::class,
|
||||
'auth' => \App\Http\Middleware\CheckAuthenticated::class,
|
||||
'verified' => \App\Http\Middleware\CheckUserVerified::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'admin' => \App\Http\Middleware\CheckAdministrator::class,
|
||||
'player' => \App\Http\Middleware\CheckPlayerExist::class,
|
||||
'setup' => \App\Http\Middleware\CheckInstallation::class,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
21
app/Http/Middleware/CheckUserVerified.php
Normal file
21
app/Http/Middleware/CheckUserVerified.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
class CheckUserVerified
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$result = (new CheckAuthenticated)->handle($request, $next, true);
|
||||
|
||||
if ($result instanceof Response) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (! $result->verified) {
|
||||
abort(403, trans('auth.check.verified'));
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
24
resources/assets/src/js/user/verification.js
Normal file
24
resources/assets/src/js/user/verification.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
$('#send-verification-email').click(async () => {
|
||||
try {
|
||||
const { errno, msg } = await fetch({
|
||||
type: 'POST',
|
||||
url: url('user/email-verification'),
|
||||
dataType: 'json',
|
||||
beforeSend: () => {
|
||||
$('#send-verification-email').hide();
|
||||
$('#sending-indicator').show();
|
||||
}
|
||||
});
|
||||
|
||||
swal({
|
||||
type: errno === 0 ? 'success' : 'warning',
|
||||
html: msg
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
showAjaxError(error);
|
||||
}
|
||||
|
||||
$('#send-verification-email').show();
|
||||
$('#sending-indicator').hide();
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@ login:
|
|||
|
||||
check:
|
||||
anonymous: Illegal access. Please log in first.
|
||||
verified: To access this page, you should verify your email address first.
|
||||
admin: Only admins are permitted to access this page.
|
||||
banned: You are banned on this site. Please contact the admin.
|
||||
token: Invalid token. Please log in.
|
||||
|
|
@ -53,6 +54,14 @@ bind:
|
|||
introduction: Email addresses will be used for password resetting. We won't send you any spam.
|
||||
registered: The email address is already registered.
|
||||
|
||||
verify:
|
||||
title: Email Verification
|
||||
success: Your account was now verified.
|
||||
message: Welcome to :sitename!
|
||||
button: Homepage
|
||||
invalid: Invalid link.
|
||||
expired: This link is expired, please resend a verification email.
|
||||
|
||||
validation:
|
||||
identification: Invalid format of email or player name.
|
||||
email: Email format is invalid.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ last-sign: Last signed at :time
|
|||
sign-remain-time: Available after :time :unit
|
||||
announcement: Announcement
|
||||
|
||||
verification:
|
||||
frequent-mail: You click the send button too fast. Wait for :remain secs, guy.
|
||||
verified: Your account is already verified.
|
||||
success: Verification link was sent, please check your inbox.
|
||||
failed: We failed to send you the verification link. Detailed message :msg
|
||||
notice:
|
||||
title: Verify Your Account
|
||||
message: You must verify your email address before using the skin hosting service. Haven't received the email?
|
||||
resend: Click here to send again.
|
||||
sending: Sending...
|
||||
mail:
|
||||
title: Verify Your Account on :sitename
|
||||
message: You are receiving this email because someone registered an account with this email address on :sitename.
|
||||
reset: "Click here to verify your account: :url"
|
||||
ignore: If you did not register an account, no further action is required.
|
||||
|
||||
score-intro:
|
||||
title: What is score?
|
||||
introduction: |
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ login:
|
|||
|
||||
check:
|
||||
anonymous: 非法访问,请先登录
|
||||
verified: 你必须验证邮箱后才能访问此页面
|
||||
admin: 看起来你并不是管理员哦
|
||||
banned: 你已经被本站封禁啦,请联系管理员解决
|
||||
token: 无效的 token,请重新登录
|
||||
|
|
@ -53,6 +54,13 @@ bind:
|
|||
introduction: 邮箱地址仅用于重置密码,我们将不会向您发送任何垃圾邮件
|
||||
registered: 该邮箱已被占用
|
||||
|
||||
verify:
|
||||
title: 邮箱验证
|
||||
success: 邮箱验证成功
|
||||
message: 欢迎使用 :sitename!
|
||||
button: 返回首页
|
||||
invalid: 无效的链接
|
||||
expired: 链接已失效,请重新发送验证邮件
|
||||
|
||||
validation:
|
||||
identification: 邮箱或角色名格式错误
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ last-sign: 上次签到于 :time
|
|||
sign-remain-time: :time :unit 后可签到
|
||||
announcement: 公告
|
||||
|
||||
verification:
|
||||
frequent-mail: 你邮件发送得太频繁啦,过 :remain 秒后再点发送吧
|
||||
verified: 你已经验证过邮箱了
|
||||
success: 验证邮件已发送,请检查你的收件箱。
|
||||
failed: 邮件发送失败,详细信息::msg
|
||||
notice:
|
||||
title: 验证你的邮箱地址
|
||||
message: 你必须验证你的邮箱才能正常使用本站的皮肤托管等功能。没有收到验证邮件?
|
||||
resend: 点击这里再次发送。
|
||||
sending: 正在发送……
|
||||
mail:
|
||||
title: 验证您在 :sitename 上的账户邮箱
|
||||
message: 您收到这封邮件,是因为有人在 :sitename 注册时使用了本邮箱地址。
|
||||
reset: 点击此链接验证您的邮箱::url
|
||||
ignore: 如果您并没有访问过我们的网站,或没有进行上述操作,请忽略这封邮件。
|
||||
|
||||
score-intro:
|
||||
title: 积分是个啥?
|
||||
introduction: |
|
||||
|
|
|
|||
32
resources/views/auth/verify.tpl
Normal file
32
resources/views/auth/verify.tpl
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
@extends('auth.master')
|
||||
|
||||
@section('title', trans('auth.verify.title'))
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<a href="{{ url('/') }}">{{ option_localized('site_name') }}</a>
|
||||
</div>
|
||||
<!-- /.login-logo -->
|
||||
<div class="login-box-body">
|
||||
<p class="login-box-msg">{{ trans('auth.verify.message', ['sitename' => option_localized('site_name')]) }}</p>
|
||||
|
||||
<div class="callout callout-success">
|
||||
<i class="icon fa fa-check"></i> {{ trans('auth.verify.success') }}
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6 pull-right">
|
||||
<a href="{{ url('/') }}" class="btn btn-primary btn-block btn-flat">
|
||||
{{ trans('auth.verify.button') }}
|
||||
</a>
|
||||
</div><!-- /.col -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- /.login-box-body -->
|
||||
</div>
|
||||
<!-- /.login-box -->
|
||||
|
||||
@endsection
|
||||
12
resources/views/common/email-verification.tpl
Normal file
12
resources/views/common/email-verification.tpl
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<div class="callout callout-info">
|
||||
<h4><i class="fa fa-envelope"></i> {{ trans('user.verification.notice.title') }}</h4>
|
||||
<p>{{ trans('user.verification.notice.message') }}
|
||||
<a id="send-verification-email" href="javascript:;">
|
||||
{{ trans('user.verification.notice.resend') }}
|
||||
</a>
|
||||
<span id="sending-indicator" style="display:none;">
|
||||
<i class="fa fa-spin fa-spinner"></i>
|
||||
{{ trans('user.verification.notice.sending') }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
3
resources/views/mails/email-verification.tpl
Normal file
3
resources/views/mails/email-verification.tpl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<p>{!! trans('user.verification.mail.message', ['sitename' => option_localized('site_name')]) !!}</p>
|
||||
<p>{!! trans('user.verification.mail.reset', ['url' => $url]) !!}</p>
|
||||
<p>{!! trans('user.verification.mail.ignore') !!}</p>
|
||||
|
|
@ -19,6 +19,11 @@
|
|||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
|
||||
@if (! $user->verified)
|
||||
@include('common.email-verification')
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<!-- Left col -->
|
||||
<div class="col-md-8">
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
<!-- Main content -->
|
||||
<section class="content">
|
||||
|
||||
<div class="row">
|
||||
|
||||
</div><!-- /.row -->
|
||||
@if (! $user->verified)
|
||||
@include('common.email-verification')
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@
|
|||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
|
||||
@if (! $user->verified)
|
||||
@include('common.email-verification')
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@ Route::group(['prefix' => 'auth'], function ()
|
|||
Route::post('/login', 'AuthController@handleLogin');
|
||||
Route::post('/register', 'AuthController@handleRegister');
|
||||
Route::post('/forgot', 'AuthController@handleForgot');
|
||||
|
||||
Route::post('/reset', 'AuthController@handleReset');
|
||||
|
||||
Route::get ('/verify', 'AuthController@verify');
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -52,15 +53,21 @@ Route::group(['middleware' => 'auth', 'prefix' => 'user'], function ()
|
|||
Route::post('/profile', 'UserController@handleProfile');
|
||||
Route::post('/profile/avatar', 'UserController@setAvatar');
|
||||
|
||||
// Email Verification
|
||||
Route::post('/email-verification', 'UserController@sendVerificationEmail');
|
||||
|
||||
// Player
|
||||
Route::any ('/player', 'PlayerController@index');
|
||||
Route::post('/player/add', 'PlayerController@add');
|
||||
Route::any ('/player/show', 'PlayerController@show');
|
||||
Route::post('/player/preference', 'PlayerController@setPreference');
|
||||
Route::post('/player/set', 'PlayerController@setTexture');
|
||||
Route::post('/player/texture/clear', 'PlayerController@clearTexture');
|
||||
Route::post('/player/rename', 'PlayerController@rename');
|
||||
Route::post('/player/delete', 'PlayerController@delete');
|
||||
Route::group(['middleware' => 'verified'], function ()
|
||||
{
|
||||
Route::any ('/player', 'PlayerController@index');
|
||||
Route::post('/player/add', 'PlayerController@add');
|
||||
Route::any ('/player/show', 'PlayerController@show');
|
||||
Route::post('/player/preference', 'PlayerController@setPreference');
|
||||
Route::post('/player/set', 'PlayerController@setTexture');
|
||||
Route::post('/player/texture/clear', 'PlayerController@clearTexture');
|
||||
Route::post('/player/rename', 'PlayerController@rename');
|
||||
Route::post('/player/delete', 'PlayerController@delete');
|
||||
});
|
||||
|
||||
// Closet
|
||||
Route::get ('/closet', 'ClosetController@index');
|
||||
|
|
@ -80,7 +87,7 @@ Route::group(['prefix' => 'skinlib'], function ()
|
|||
Route::any('/show/{tid}', 'SkinlibController@show');
|
||||
Route::any('/data', 'SkinlibController@getSkinlibFiltered');
|
||||
|
||||
Route::group(['middleware' => 'auth'], function ()
|
||||
Route::group(['middleware' => ['auth', 'verified']], function ()
|
||||
{
|
||||
Route::get ('/upload', 'SkinlibController@upload');
|
||||
Route::post('/upload', 'SkinlibController@handleUpload');
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user