Commit d4077bde authored by UtopiaXC's avatar UtopiaXC

📨 完成邮件发送,修改Redis工具,更改验证码保存方式

parent 7db4a661
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Utils\CustomCaptcha;
use App\Http\Utils\R;
use App\Http\Utils\RedisAndCache;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Mews\Captcha\Captcha;
class CaptchaController extends Controller{
function getCaptcha(Request $request, Captcha $captchaBuilder)
{
class CaptchaController extends Controller {
function getCaptcha(Request $request, Captcha $captchaBuilder) {
//获取laravel的session token,这里的思想是通过缓存token与验证码值来验证以避免重复提交同一hash问题
$key = $request->cookie(app()->getNamespace() . "session");
$key = $request->cookie(env("APP_NAME", "utopia_open_platform") . "_session");
//创建自定义验证码对象,需要将构建器传入
$captcha = new CustomCaptcha($captchaBuilder);
//设置过期时间。我设置了两分钟
$expiredAt = now()->addMinute(2);
$expiredAt = now()->addMinutes(2);
//将验证码值,session token放入缓存并设置过期时间
Cache::put($key, ['captcha' => $captcha->getCode()], $expiredAt);
RedisAndCache::setWithExpire(\RedisCacheKey::CAPTCHA . $key, $captcha->getCode(), 2);
//构建返回数组,包括有效期截止时间和BASE64格式图片
$result = [
'expired_at' => $expiredAt->toDateTimeString(),
......@@ -28,18 +27,20 @@ class CaptchaController extends Controller{
return R::ok($result);
}
//验证用户提交的验证码,返回值bool(私有方法)
static function check_captcha($captcha,$session):bool{
//验证用户提交的验证码,返回值bool
static function check_captcha($request) {
$captcha = $request->get(\FormKey::CAPTCHA);
$session = \RedisCacheKey::CAPTCHA . $request->cookie(env("APP_NAME", "utopia_open_platform") . "_session");
//通过传入的session获取缓存中的验证码对象,不存在则返回验证失败
$captchaData = Cache::get($session);
Cache::forget($session);
$captchaData = RedisAndCache::get($session);
RedisAndCache::forget($session);
if ($captchaData == null) {
return false;
}
//判断传入的验证码与缓存是否相等
if ($captcha == $captchaData['captcha']){
if ($captcha == $captchaData) {
return true;
}else{
} else {
return false;
}
}
......
......@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
use App\Http\Utils\R;
use App\Http\Utils\RedisAndCache;
use App\Mail\RegisterVerifyLinkMail;
use App\Models\Users\User;
use App\Models\Users\UserProfile;
use Exception;
......@@ -11,21 +12,25 @@ use HTTP_CODE;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\DB;
use Mail;
use RedisCacheKey;
use Webpatser\Uuid\Uuid;
class UserController extends Controller {
/**
* @throws \Throwable
*/
function register(Request $request) {
if (!CaptchaController::check_captcha($request->get("captcha"), $request->cookie(app()->getNamespace() . "session"))) {
if (!CaptchaController::check_captcha($request)) {
return R::error(HTTP_CODE::UNAUTHORIZED_CAPTCHA);
}
try {
if (!$request->get("email") || !$request->get("user_name") || !$request->get("password")) {
if (!$request->get(\FormKey::EMAIL) || !$request->get(\FormKey::EMAIL) || !$request->get(\FormKey::PASSWORD)) {
return R::error(HTTP_CODE::NOT_ACCEPT_PARAMS_CONTENT_WRONG);
}
$email = $request->get("email");
$user_name = $request->get("user_name");
$password = password_hash($request->get("password"), PASSWORD_DEFAULT);
$email = $request->get(\FormKey::EMAIL);
$user_name = $request->get(\FormKey::USER_NAME);
$password = password_hash($request->get(\FormKey::PASSWORD), PASSWORD_DEFAULT);
$user = User::query()
->where("user_name", $user_name)
->orWhere("user_name", $email)
......@@ -47,6 +52,10 @@ class UserController extends Controller {
$user->save();
$user_profile->save();
DB::commit();
$code = md5(Uuid::generate());
$link = env("APP_URL") . \WebUrl::REGISTER_VERIFY . "/" . $code;
R::ok(RedisAndCache::setWithExpire(RedisCacheKey::REGISTER_VERIFY . $code, $user->id,15));
Mail::to($email)->send(new RegisterVerifyLinkMail($link, $user_name));
} catch (Exception $e) {
DB::rollBack();
return R::error(HTTP_CODE::INTERNAL_SERVER_ERROR);
......@@ -55,11 +64,11 @@ class UserController extends Controller {
}
function login(Request $request) {
if (!CaptchaController::check_captcha($request->get("captcha"), $request->cookie(app()->getNamespace() . "session"))) {
if (!CaptchaController::check_captcha($request)) {
return R::error(HTTP_CODE::UNAUTHORIZED_CAPTCHA);
}
$username = $request->get("user");
$password = $request->get("password");
$username = $request->get(\FormKey::USER);
$password = $request->get(\FormKey::PASSWORD);
if (!$username || !$password) {
return R::error(HTTP_CODE::NOT_ACCEPT_PARAMS_CONTENT_WRONG);
}
......
......@@ -61,7 +61,6 @@ class RedisAndCache {
return $value;
}
public static function getWithJson($key) {
try {
if (env(EnvKey::REDIS_USE, false) == true) {
......@@ -78,4 +77,21 @@ class RedisAndCache {
}
return $value;
}
public static function forget($key) {
try {
if (env(EnvKey::REDIS_USE, false) == true) {
try {
Redis::del($key);
} catch (ConnectionException $e) {
Cache::forget($key);
}
} else {
Cache::forget($key);
}
} catch (Exception $e) {
return false;
}
return true;
}
}
......@@ -7,7 +7,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class VerityLinkMail extends Mailable {
class RegisterVerifyLinkMail extends Mailable {
use Queueable, SerializesModels;
protected $link;
......@@ -20,8 +20,8 @@ class VerityLinkMail extends Mailable {
*/
public function __construct($link, $user) {
//
$this->$user = $user;
$this->$link = $link;
$this->user = $user;
$this->link = $link;
}
/**
......@@ -33,6 +33,6 @@ class VerityLinkMail extends Mailable {
return $this->view('email.register_verify_link')->with([
"link" => $this->link,
"user" => $this->user,
]);
])->from(['address' => env("MAIL_FROM_ADDRESS"), 'name' => env("APP_NAME")]);
}
}
......@@ -8,6 +8,7 @@ class WebUrl
const FIND_PASSWORD = '/find_password';
const PRIVACY_POLICY = "/privacy_policy";
const REGISTER_VERIFY="/register_verify";
}
class ApiUrl
......@@ -44,6 +45,8 @@ class RedisCacheKey
{
const SITE_PROFILE = "site_profile";
const USER_TOKEN = "user_token:";
const REGISTER_VERIFY="register_verify:";
const CAPTCHA="captcha:";
}
class CookieKey
......@@ -58,6 +61,14 @@ class HeaderKey
const SITE_PROFILE="site_profile";
}
class FormKey{
const CAPTCHA="captcha";
const USER_NAME="user_name";
const EMAIL="email";
const PASSWORD="password";
const USER="user";
}
class SiteProfileTypeEnum
{
const WEB_TITLE = "01";
......@@ -75,3 +86,4 @@ class DefaultSiteProfile
class EnvKey{
const REDIS_USE="REDIS_USE";
}
......@@ -3,5 +3,5 @@
@section('title') - 注册验证 @endsection
@section('body')
注册验证页
{{$code}}
@endsection
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" >
<head>
<meta charset="UTF-8">
<title>CodePen - Material VCard</title>
<style>
@import url(https://fonts.googleapis.cn/css?family=Open+Sans:400,300,700);
* {
<body style="
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
background-color: #eaeaea;
font-family: Open Sans;
font-family: Open Sans, sans-serif;
font-weight: 300;
line-height: 1.8;
background-size: cover;
background-repeat: no-repeat;
}
.contact {
position: absolute;
top: 30px;
left: 50px;
z-index: 6;
color: rgba(0, 0, 0, 0.5);
text-transform: uppercase;
letter-spacing: 3px;
font-size: 12px;
font-weight: 700;
padding: 5px 15px;
border-radius: 20px;
background: rgba(0, 0, 0, 0.1);
line-height: 1;
cursor: pointer;
text-shadow: 0 1px 0px rgba(255, 255, 255, 0.1);
}
.contact-form {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: white;
z-index: 5;
padding: 80px 50px;
transform: translate3d(-100%, 0, 0);
transition: 0.3s ease;
border-radius: 5px;
}
.contact-form.active {
transform: translate3d(0, 0, 0);
}
.contact-form .close {
color: rgba(0, 0, 0, 0.7);
position: absolute;
right: 30px;
top: 30px;
}
.cards {
background-repeat: no-repeat;">
<div style="
box-sizing: border-box;
margin: auto;
background: #fefefe;
border-radius: 5px;
......@@ -71,207 +20,52 @@
position: relative;
display: flex;
align-items: flex-end;
padding: 30px;
}
.cards .card {
display: inline-block;
margin-right: 20px;
}
.cards .card-toggle {
z-index: 4;
position: relative;
width: 48px;
height: 48px;
border-radius: 50%;
display: block;
text-align: center;
line-height: 1.8;
font-size: 24px;
cursor: pointer;
border: 2px solid transparent;
transition: 0.3s ease;
}
.cards .card-toggle.active {
color: white;
border-color: white;
}
.cards .card-content {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
transition: -webkit-clip-path 1s ease;
padding: 100px 0 0;
overflow: hidden;
border-radius: 5px;
}
.cards .card-content .row {
display: table;
width: 100%;
height: 100%;
}
.cards .card-content .col {
width: 70%;
height: 100%;
display: table-cell;
transition: 0.3s ease 0.3s;
transform: translate3d(0, 0, 0);
vertical-align: top;
}
.cards .card-content .col h2 {
font-weight: 300;
font-size: 3em;
line-height: 1;
margin: 0 0 30px;
}
.cards .card-content .col h2 strong {
font-weight: 700;
display: block;
}
.cards .card-content .col img {
max-width: 90%;
width: 100%;
}
.cards .card-content .col.left {
transform: translate3d(0, 0, 0);
opacity: 0;
padding-left: 50px;
}
.cards .card-content .col.right {
transform: translate3d(100px, 0, 0);
opacity: 0;
padding-left: 30px;
}
.cards .card.active .col {
transform: translate3d(0, 0, 0);
opacity: 1;
}
.cards #overview .card-toggle {
position: absolute;
top: 30px;
right: 30px;
opacity: 1;
color: white;
}
.cards #overview .card-content {
background-color: #efefef;
-webkit-clip-path: circle(0% at 91.5% 75px);
}
.cards #overview.active .card-toggle {
opacity: 0;
}
.cards #overview.active .card-content {
-webkit-clip-path: circle(270% at 91.5% 75px);
}
.cards #overview .right {
background-size: contain;
}
.cards #dribbble .card-content, .cards #behance .card-content, .cards #linkedin .card-content, .cards #twitter .card-content {
color: white;
}
.cards #dribbble .card-content p, .cards #behance .card-content p, .cards #linkedin .card-content p, .cards #twitter .card-content p {
color: rgba(255, 255, 255, 0.8);
}
.cards #dribbble .card-content {
background-color: #F46899;
-webkit-clip-path: circle(0% at 76px 88%);
clip-path: circle(0% at 50px 88%);
}
.cards #dribbble.active .card-content {
-webkit-clip-path: circle(270% at 76px 88%);
clip-path: circle(270% at 50px 88%);
}
.cards #behance .card-content {
background-color: #2F98D1;
-webkit-clip-path: circle(0% at 150px 88%);
clip-path: circle(0% at 150px 88%);
}
.cards #behance.active .card-content {
-webkit-clip-path: circle(270% at 150px 88%);
clip-path: circle(270% at 150px 88%);
}
.cards #linkedin .card-content {
background-color: #03679B;
-webkit-clip-path: circle(0% at 220px 88%);
clip-path: circle(0% at 220px 88%);
}
.cards #linkedin.active .card-content {
-webkit-clip-path: circle(270% at 220px 88%);
clip-path: circle(270% at 220px 88%);
}
.cards #twitter .card-content {
background-color: #7FD0ED;
-webkit-clip-path: circle(0% at 292px 88%);
clip-path: circle(0% at 292px 88%);
}
.cards #twitter.active .card-content {
-webkit-clip-path: circle(270% at 292px 88%);
clip-path: circle(270% at 292px 88%);
}
form .control {
position: relative;
margin-bottom: 10px;
padding-top: 20px;
}
form .control label {
position: absolute;
top: 30px;
left: 0;
transition: 0.3s ease;
text-transform: uppercase;
font-weight: 600;
letter-spacing: 2px;
font-size: 14px;
}
form .control.submit {
text-align: right;
}
form input, form textarea {
width: 100%;
border: none;
border-bottom: 1px solid #e3e3e3;
outline: none;
padding: 10px 0;
}
form .filled label, form input:focus + label, form textarea:focus + label {
top: 0;
font-size: 12px;
}
form textarea {
height: 100px;
}
form input[type=submit] {
width: auto;
background-color: #F06292;
padding: 10px 40px;
color: white;
border-radius: 40px;
}
</style>
</head>
<body>
<div class="cards">
<div class="contact" onclick="window.open('{{env('APP_URL','https://open.utopiaxc.cn/')}}')">Utopia Open Platform</div>
<div class="card active">
<div class="card-content">
<div class="row">
<div class="left col">
<h2>欢迎注册<br>{{env('APP_SHOW_NAME','Utopia Open Platform')}}</h2>
<p>亲爱的 {{$user}}<br>您已成功注册{{env('APP_SHOW_NAME','Utopia Open Platform')}}的账户,请点击<a target="_blank" href="{{$link}}">验证链接</a>来激活您的账户功能。验证有效期十五分钟。 <br/><em>如果您点击链接后未跳转,请将以下链接复制到浏览器访问:<br>{{$link}}</em></p>
padding: 30px;" class="cards">
<div style="
box-sizing: border-box;
display: inline-block;
margin-right: 20px;">
<div style="
box-sizing: border-box;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
transition: -webkit-clip-path 1s ease;
padding: 100px 0 0;
overflow: hidden;
border-radius: 5px;">
<div style="
box-sizing: border-box;
display: table;
width: 100%;
height: 100%;">
<div style="
box-sizing: border-box;
transform: translate3d(0, 0, 0);
padding-left: 50px;
opacity: 1;">
<h2 style="
box-sizing: border-box;
font-weight: 300;
font-size: 3em;
line-height: 1;
margin: 0 0 30px;">欢迎注册<br>{{env('APP_SHOW_NAME','Utopia Open Platform')}}</h2>
<p style="width: 70%">亲爱的 {{$user}}<br>您已成功注册{{env('APP_SHOW_NAME','Utopia Open Platform')}}
的账户,请点击<a target="_blank" href="{{$link}}">验证链接</a>来激活您的账户功能。验证有效期十五分钟。 <br/><em>如果您点击链接后未跳转,请将以下链接复制到浏览器访问:<br>{{$link}}
</em></p>
</div>
<div class="right col">
<div style="
text-align: right;
padding-right: 100px">
<p>
<a target="_blank"
href="{{env('APP_URL',"")}}">{{env('APP_SHOW_NAME','Utopia Open Platform')}}</a>
</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
......@@ -23,7 +23,7 @@ Route::group(['prefix' => '/', 'middleware' => [Middleware::SITE_PROFILE_MIDDLEW
Route::get("/register", function () {
return view('register');
});
Route::get("/register_verify", function () {
return view('email.register_verify');
Route::get("/register_verify/{code}", function ($code) {
return view('email.register_verify')->with("code",$code);
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment