流程图
在做业务逻辑前,我们需要做一个流程图,确保用户所走的业务逻辑不会出现死循环或者陷入死胡同。
效果图
步骤
1、前端页面
src/views/login.vue
<template>
<input
class="input_box"
type="email"
v-model="email"
autocomplete="off"
placeholder="Your email">
<div class="pwd_note">{
{email_note}}</div>
<input
class="input_box"
type="password"
v-model="password"
autocomplete="off"
placeholder="Your password">
<div class="pwd_note">{
{password_note}}</div>
<div class="slider_vue">
<div>
<div @mousedown="slider_down"
:style="{'margin-left':left+'px'}"></div>
</div>
<div v-show="show_pic">
<div :style="{'left':little_left+'px','top':true_top+'px','background-position-y':-true_top+'px','background-position-x':-true_left-50+'px'}"></div>
<div :style="{'left':true_left+'px','top':true_top+'px'}"></div>
</div>
</div>
</template>
<script>
methods:{
login_event:function(){
let that = this;
let email_vertify = /^([a-zA-Z]|[0-9])(\w)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
if(that.email == ''){
that.email_note = '请输入您的邮箱';
}else if(!email_vertify.test(that.email)){
that.email_note = '请输入正确格式的邮箱';
}else{
that.email_note = '';
}
let pwd_vertify = /^(\w){8,20}$/;
if(that.password == ''){
that.password_note = "请输入您的密码";
}else if(!pwd_vertify.test(that.password)){
that.password_note = '密码应为字母、数字组合的8-20位字符';
}else{
that.password_note = '';
}
if(that.email_note == '' && that.password_note == ''){
let data={'email':that.email,'password':that.password};
axios.post('/api/send',data).then(res=>{
if(res.data[0] == 3){ //登录成功
alert("state: "+res.data[0] + " note: " + res.data[1]);
that.$router.push('/person');
}else{
alert("state: "+res.data[0] + " note: " + res.data[1]);
}
})
}
},
slider_down:function(e){
let that = this;
that.show_pic = 1;
if(!that.true_left)
that.ran();
let disX = e.clientX;
let left_origin = that.left;
let little_left_origin = that.little_left;
document.onmousemove = (e) =>{
let margin_left = e.clientX-disX;
if(that.left >= 10 && that.left <=270){
that.left = left_origin + margin_left;
that.little_left = little_left_origin + margin_left;
}
if(that.left < 10){
that.left = 10;
that.little_left = 5;
}
if(that.left > 270){
that.left = 270;
that.little_left = 265;
}
},
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
if(that.true_left == that.little_left-50 ||
that.true_left == that.little_left-51 ||
that.true_left == that.little_left-49 ){
that.login_event();
}
}
},
ran:function(){
let top_max = 100;
let left_max = 195;
this.true_top = Math.floor(Math.random() * top_max ) + 5;
this.true_left = Math.floor(Math.random() * left_max ) + 20;
}
}
</script>
<style lang="scss">
.input_box{
width:300px;
border:0;
border-bottom: 1px solid black;
background-color: rgba(0,0,0,0);
outline:none;
padding: 10px;
padding-top: 0;
height: 30px;
}
.pwd_note{
border:0;
font-size: 15px;
width: 310px;
padding-left: 10px;
text-align: left;
height: 30px;
margin-bottom: 30px;
color:grey;
}
$slider_width:320px;
$slider_height:60px;
$ball_height:40px;
$picture_height:160px;
.slider_vue{
width:$slider_width;
height: $slider_height;
margin-bottom: 30px;
>div:first-child{
width:$slider_width;
height: $slider_height;
background-image: url('/images/sign.png');
background-size: cover;
display: flex;
align-items: center;
border-radius: $slider_height;
>div{
width: $ball_height - 2px;
height: $ball_height - 2px;
border-radius: $ball_height;
border:1px solid black;
background-color: rgb(253, 227, 187);
}
}
>div:last-child{
animation: show 1s;
width: $slider_width;
height: $picture_height;
background-color: rgb(184, 112, 112);
position: relative;
border-radius: 5px;
bottom: $picture_height + $slider_height + 10px;
background-image:url("/images/picture.jpg");
display: flex;
box-shadow: 0 0 5px black;
>div{
width: 50px;
height: 50px;
position: relative;
border-radius: 5px;
}
>div:first-child{
background-image: url('/images/picture.jpg');
background-color: #fff;
background-repeat: no-repeat;
background-position-x: -150px;
background-position-y: -30px;
box-shadow: 0 0 10px black;
left: 5px;
top:30px;
z-index: 10;
}
>div:last-child{
background-color: rgba(0, 0, 0,0.3);
box-shadow: 0 0 10px black inset;
left: 100px;
top:30px;
}
}
}
@keyframes show {
0% {opacity: 0;}
100% {opacity: 1;}
}
</style>
2、申请一个163邮箱,设置开启stmp服务
3、在服务器打开465端口,并在laravel的.env文件配置邮箱:
MAIL_DRIVER=smtp
MAIL_HOST=smtp.163.com
MAIL_PORT=465
MAIL_USERNAME=你的邮箱@163.com
MAIL_PASSWORD=开启stmp的授权码
MAIL_ENCRYPTION=ssl
MAIL_FROM_ADDRESS=你的邮箱@163.com
MAIL_FROM_NAME="${APP_NAME}"
4、数据库的用户表
CREATE TABLE `users` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`nickname` varchar(10) CHARACTER SET utf8 NOT NULL DEFAULT 'nickname',
`email` varchar(255) NOT NULL,
`password` varchar(255) CHARACTER SET utf8 NOT NULL,
`avatar` varchar(255) DEFAULT NULL,
`token` varchar(255) DEFAULT NULL,
`create_at` varchar(12) NOT NULL,
`update_at` varchar(12) DEFAULT NULL,
PRIMARY KEY (`id`,`email`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
5、发送邮件的路由和接口
//发送验证邮件
Route::post('/send','UserController@send');
public function send(Request $request){
$state[] = [];
$email = $request->email;
$password = $request->password;
//查询是否已创建账户
$user = DB::table('users')->where('email',$email)->first();
if($user==null){//未创建,则创建账户,并发送验证邮件
$time = date('YmdHis',time());
$token = getString(15);
$id = DB::table('users')->insertGetId([
'nickname'=>'user_'.$time,
'email'=>$email,
'password'=>md5($password),
'avatar'=>'/default_avatar.png',
'create_at'=>time(),
'token'=>$token
]);
$subject = '揽阅LanYue邮箱验证';
Mail::send('mail',['id'=>$id,'token'=>$token],
function($message)use($email,$subject){
$message->to($email);
$message->subject($subject);
});
$state[0] = 0;
$state[1] = "欢迎使用揽阅。您的账户还未激活,揽阅已为您发送激活邮件,请在十分钟内验证邮箱。";
}else{//已创建
if($user->update_at == null){ //未激活,发送验证邮件
$token = getString(15);
DB::table('users')->where('email',$email)->update([
'password'=>$password,
'token'=>$token
]);
$subject = '揽阅LanYue邮箱验证';
Mail::send('mail',['id'=>$user->id,'token'=>$token],
function($message)use($email,$subject){
$message->to($email);
$message->subject($subject);
});
$state[0] = 1;
$state[1] = "您的账户还未激活,揽阅已为您发送激活邮件,请在十分钟内验证邮箱。";
}else{ //已激活
if(md5($password) == $user->password){ //密码相同,登录
if(Cookie::get('token') == $user->token){
$state[0] = 2;
$state[1] = "您已登录,无需重复登录";
}else{
Cookie::queue('token', $user->token, 60);
$state[0] = 3;
$state[1] = "登录成功";
$state['id'] = $user->id;
$state['nickname'] = $user->nickname;
$state['avatar'] = $user->avatar;
}
}else{ //登录失败
$state[0] = 3;
$state[1] = "密码错误";
}
}
}
return response()->json($state);
}
6、新建blade模板:resources/views/mail.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>您好,欢迎使用揽阅LanYue。请在十分钟内验证您的邮箱账户,谢谢配合!</div>
<a href="http://www.***.com/vertify/{
{$id}}/{
{$token}}">点击验证</a>
</body>
</html>
7、vue路由与页面
src/route/index.js
import Vertify from '../views/Vertify.vue'
const routes = [
......
{
path:'/vertify/:id/:token',
name:'vertify',
component:Vertify
}
]
src/view/Vertify.vue
<template>
<div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name:'vertify',
data(){
return{
}
},
mounted(){
let id = this.$route.params.id;
let token = this.$route.params.token;
axios.get('/api/vertify',{
params:{'id':id,'token':token}
}).then(res=>{
alert(res.data);
})
}
}
</script>
8、邮件验证的路由和接口
//邮件验证
Route::get('/vertify','UserController@vertify');
public function vertify(Request $request){
$state[] = [];
$id = $request->id;
$token = $request->token;
$user = DB::table('users')->find($id);
$update_at = time();
if($user->token == ''){
$state[0] = 0;
$state[1] = "重复验证无效";
}else if($update_at - $user->create_at > 600){
$state[0] = 1;
$state[1] = "验证过时,请重新发送验证邮件";
}else if($token != $user->token){
$state[0] = 2;
$state[1] = "token错误,请重新发送验证邮件或联系客服";
}else if($update_at - $user->create_at <= 600 && $token == $user->token){
//token未过时且正确
DB::table('users')->where('id',$id)->update([
'update_at'=>$update_at
]);
$state[0] = 3;
$state[1] = "验证成功";
$state['id'] = $user->id;
$state['nickname'] = $user->nickname;
$state['avatar'] = $user->avatar;
Cookie::queue('token', $user->token, 60);
}
return response()->json($state);
}
9、获取用户信息
Person.vue
mounted(){
let that = this;
axios.get('/api/userInfo').then(res=>{
if(res.data[0] == 2){
that.global.nickname = res.data['nickname'];
that.global.nickpath = '/person';
that.avatar = "http://lanyue.ink/api/"+res.data['avatar'];
that.pre_avatar = "http://lanyue.ink/api/"+res.data['avatar'];
}else{
that.global.nickname = 'Login';
that.global.nickpath = '/login';
that.$router.push('/login');
}
});
},
//路由
Route::post('/userInfo','UserController@userInfo');
//接口
public function userInfo(){
$state[] = [];
$token = Cookie::get('token');
if($token == null){
$state[0] = 0;
$state[1] = "找不到token";
}else{
$user = DB::table('users')->where('token',$token)->get();
if($user[0] == null){
$state[0] = 1;
$state[1] = "token错误";
}else{
$state[0] = 2;
$state[1] = "用户信息找到";
$state['id'] = $user[0]->id;
$state['nickname'] = $user[0]->nickname;
$state['avatar'] = $user[0]->avatar;
}
}
return response()->json($state);
}
ok