登录注册接口实现
后端
import re
from rest_framework.views import APIView
from utils.response import APIResponse
from utils.auth import cache_token,clear_token,need_token
from libs.ali_sms import get_code
from django.core.cache import cache
# Create your views here.
from .throttles import SMSThrottle
from . import serializers
from . import models
class SMSAPIView(APIView):
throttle_classes = [SMSThrottle]
def post(self,request,*args,**kwargs):
mobile = request.data.get('mobile')
if not mobile or not re.match(r'^1[3-9][0-9]{9}$', mobile):
return APIResponse(1, '手机号有误')
# 产生验证码
code = get_code()
# 通知第三方发送短信
# result = send_sms(mobile,code)
# 失败:
# if not result:
# return APIResponse(1,'短信发送失败')
# 成功设置到redis数据库里面:
print(code)
cache.set(f'{mobile}_code',code,5*60)
# print(cache.get(f'{mobile}_code'))
return APIResponse(0,'短信发送成功')
class MobileAPIView(APIView):
def get(self,request,*args,**kwargs):
# 获取手机号
mobile = request.query_params.get('mobile')
if not mobile:
return APIResponse(1,'手机号必须提供')
# 校验手机号是否合法
if not re.match(r'^1[3-9][0-9]{9}$',mobile):
return APIResponse(1,'手机号有误')
try:
models.User.objects.get(mobile=mobile, is_active=True)
return APIResponse(1,'手机已注册')
except:
return APIResponse(0,'手机号未注册')
class RegisterAPIView(APIView):
def post(self,request,*args,**kwargs):
# user_ser = serializers.
# 校验
user_ser = serializers.UserModelSerializer(data=request.data)
if user_ser.is_valid():
user_ser.save()
return APIResponse(0,'注册成功',results=user_ser.data)
else:
# print(user_ser.errors)
# res = user_ser.errors.values()
# print(res)
# print()
return APIResponse(1,'注册失败',results=list(user_ser.errors.values())[0][0])
# 登录功能
from rest_framework_jwt.serializers import jwt_encode_handler ,jwt_payload_handler
class LoginAPIView(APIView):
authentication_classes = ()
permission_classes = ()
def post(self,request,*atgs,**kwargs):
username = request.data.get('username')
password = request.data.get('password')
code = request.data.get('code')
is_remeber = request.data.get('is_remeber')
if password and username:
if re.match(r'^1[3-9][0-9]{9}$', username):
try:
# 手动通过 user 签发 jwt-token
user = models.User.objects.get(mobile=username)
except:
return APIResponse(1, '该手机未注册')
else:
# 因为不是纯数字所以也就不包括手机号码,不包括手机号码就一定是用户名
if re.match(r'^/d*$', username):
return APIResponse(1,'用户名不能为纯数字')
try:
user = models.User.objects.get(username=username)
if not user.check_password(password):
return APIResponse(1,'密码错误')
except:
return APIResponse(1,'该账号未注册')
# 签发token
# payload = jwt_payload_handler(user)
# token = jwt_encode_handler(payload)
token = cache_token(request,user.id, user.password,is_remeber)
return APIResponse(0, 'ok', results={
'username': user.username,
'mobile': user.mobile,
'token': token
})
if username and code:
if not re.match(r'^1[3-9][0-9]{9}$', username):
return APIResponse(1,'手机号格式错误')
cache_code = cache.get(f'{username}_code')
cache.delete(f'{username}_code')
if code!= cache_code:
return APIResponse(1,'验证码错误')
try:
# 手动通过 user 签发 jwt-token
user = models.User.objects.get(mobile=username)
except:
return APIResponse(1, '该手机未注册')
# 签发token
# payload = jwt_payload_handler(user)
# token = jwt_encode_handler(payload)
token = cache_token(request, user.id, user.password, is_remeber)
return APIResponse(0, 'ok', results={
'username': user.username,
'mobile': user.mobile,
'token': token
})
return APIResponse(1,'参数不全')
Register
<template>
<div class="box">
<img src="@/assets/img/Loginbg.jpg" alt="">
<div class="register">
<div class="register_box">
<div class="register-title">注册路飞学城</div>
<div class="inp">
<input v-model="username" @blur="checkUser" type="text" placeholder="用户名" :class="{user:true,error:username_ver}">
<input v-model="mobile" @blur="checkMobile" type="text" placeholder="手机号码" :class="{user:true,error:mobile_ver}">
<input v-model="password" @blur="checkpassword" type="password" placeholder="用户密码" :class="{user:true,error:password_ver}">
<input v-model="repassword" @blur="checkrepassword" type="password" placeholder="再次输入用户密码" :class="{user:true,error:repassword_ver}">
<div class="sms">
<input v-model="sms" type="text" placeholder="输入验证码" class="user">
<span class="sms_btn" @click="send_sms">{{sms_interval_tips}}</span>
</div>
<div id="geetest"></div>
<button class="register_btn" @click="registerMobile">注册</button>
<p class="go_login">已有账号
<router-link to="/login">直接登录</router-link>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Register',
data() {
return {
username:"",
sms: "",
mobile: "",
password: "",
repassword: "",
username_ver:false,
sms_ver: false,
mobile_ver: false,
password_ver: false,
repassword_ver: false,
is_send: false, // 是否在60s内发送了短信
sms_interval_tips: "获取验证码",
}
},
created() {
console.log(/^[0-9a-zA-Z.]{6,16}$/.test('zmss y.'));
},
methods: {
// 校验用户名长度
checkUser(){
if (this.username.length>15){
this.$message({
message:'用户名长度不能超过15个字符',
type:'error'
});
this.username_ver = true
}else {
this.username_ver =false
}
if (/^\d*$/.test(this.username)){
this.$message({
message:'用户名不能为纯字数字',
type:'error'
});
this.username_ver = true
}else {
this.username_ver =false
}
},
checkpassword(){
if (!/^[0-9a-zA-Z.]{6,16}$/.test(this.password)){
// this.username='';
this.$message({
message:'密码只能由 /数字/字母/点/ 组成',
type:'error'
});
this.password_ver =true
}else{
this.password_ver = false
}
},
checkrepassword(){
if (this.password !== this.repassword){
this.$message({
message:'两次密码不一致',
type:'error'
});
this.repassword_ver=true
}else{
this.repassword_ver = false
}
},
// 电话号失去焦点会触发这个。
checkMobile() {
if (this.mobile.length < 1) {
return false;
}
// 手机号码格式是否正确
if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
this.$message({
message: "对不起!手机号码格式有误!"
});
this.mobile_ver=true;
return false;
}
// 验证手机号码是否已经注册了
// this.$axios.get(this.$settings.Host+"/users/mobile/"+this.mobile+"/");
this.$axios({
url: this.$settings.base_url + '/user/mobile/',
method: 'get',
params: {
mobile: this.mobile
}
}).then(response => {
let data = response.data;
window.console.log(data);
if (data.status != 0) {
this.$message({
message: "对不起!手机号码已经被注册!"
});
this.mobile_ver = true;
return false;
} else {
this.$message({
message: "期待您加入我们!"
});
this.mobile_ver = false
}
}).catch(error => {
let data = error.response.data;
this.$message({
message: data.message
})
})
},
// 发送验证码
send_sms() {
if (this.mobile.length < 1) {
this.$message({
message: "请填写手机号"
});
return false;
}
// 发送短信
if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
this.$message({
message: "对不起!手机号码格式有误!"
});
return false;
}
// 判断是否在60s内发送过短信
if (this.is_send) {
this.$message({
message: "对不起,不能频繁发送短信验证!"
});
return false;
}
// 请求发送短信
this.$axios({
url: this.$settings.base_url + '/user/sms/',
method: 'post',
data: {
mobile: this.mobile
}
}).then(response => {
this.$message({
message: response.data.msg,
type:'success'
});
// 修改短信的发送状态
this.is_send = true;
// 设置间隔时间60s
let sms_interval_time = 60;
// 设置短信发送间隔倒计时,.60s后把is_send改成false
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval_tips = "获取验证码";
this.is_send = false; // 重新恢复点击发送功能的条件
} else {
sms_interval_time -= 1;
this.sms_interval_tips = `${sms_interval_time}秒后再次获取`;
}
}, 1000);
}).catch(error => {
this.$message({
message: error.response.data.result,
})
});
},
// 注册
registerMobile() {
if (this.username.length<1){
this.$message({
message:'请填写用户名',
type:'error'
});
return false;
}
if (this.username.length>15){
this.$message({
message:'用户名长度不能超过15个字符',
type:'error'
});
this.$router.push('/login');
return false;
}
if (/^\d*$/.test(this.username)){
this.$message({
message:'用户名不能为纯字数字',
type:'error'
});
this.username_ver = true
return false
}else {
this.username_ver =false
}
// 注册信息提交
if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
this.$message({
message: "对不起!手机号码格式有误!"
});
return false;
}
if (this.sms.length < 1) {
this.$message({
message: "短信验证码不能为空!"
});
return false;
}
if (this.password.length < 6 || this.password.length > 16) {
this.$message({
message: "对不起,密码长度必须在6-16个字符之间!"
});
return false;
}
this.$axios({
url: this.$settings.base_url + '/user/register/mobile/',
method: 'post',
data: {
username:this.username,
mobile: this.mobile,
password: this.password,
repassword: this.repassword,
code: this.sms
}
}).then(response => {
// let _this = this;
let status = response.data.status;
// let msg = response.data.msg;
if (status == 0){
this.username='';
this.mobile = '';
this.password='';
this.repassword='';
this.code = '';
this.$message({
message:'注册成功!!!',
duration:2000,
type:'success',
onClose:()=>{
this.$router.push('/login')
}
})
}else{
// this.mobile = '';
// this.password = '';
// this.sms =response.result.;
// message:response.data.results,
// console.log(response.data.results)
// console.log(response.data.results[0][0])
this.$message({
message:response.data.results,
duration:1000,
})
}
}).catch(error => {
this.$message({
message: error
});
})
}
},
};
</script>
Login.vue
<template>
<div class="login box">
<img src="@/assets/img/Loginbg.jpg" alt="">
<div class="login">
<div class="login-title">
<img src="@/assets/img/Logotitle.png" alt="">
<p>帮助有志向的年轻人通过努力学习获得体面的工作和生活!</p>
</div>
<div class="login_box">
<div class="title">
<span :class="{active: a0}" @click="changeLogin(0)">密码登录</span>
<span :class="{active: a1}" @click="changeLogin(1)">短信登录</span>
</div>
<div class="inp" v-if="login_type==0">
<input v-model="username" type="text" placeholder="用户名 / 手机号码" class="user">
<input v-model="password" type="password" name="" class="pwd" placeholder="密码">
<div id="geetest1"></div>
<div class="rember">
<p>
<input id="checkbox" type="checkbox" class="no" v-model="remember"/>
<span>记住密码</span>
</p>
<p>忘记密码</p>
</div>
<button class="login_btn" @click="loginAction">登录</button>
<p class="go_login">没有账号
<router-link to="/register">立即注册</router-link>
</p>
</div>
<div class="inp" v-show="login_type==1">
<input v-model="mobile" type="text" placeholder="手机号码" class="user">
<div class="sms">
<input v-model="sms" type="text" placeholder="输入验证码" class="user">
<span class="sms_btn" @click="send_sms">{{sms_interval_tips}}</span>
</div>
<button class="login_btn" @click="loginMobile">登录</button>
<p class="go_login">没有账号
<router-link to="/register">立即注册</router-link>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
a0: 1,
a1: 0,
login_type: 0,
username: "",
password: "",
remember: false,
mobile: "",
sms: "",
is_send: false, // 是否在60s内发送了短信
sms_interval_tips: "获取验证码",
}
},
created() {
// 拦截已登录情况
let token = this.$cookies.get('token');
if (token) {
this.$message({
message: '无需重复登录',
duration: 1000,
onClose: () => {
this.$router.go(-1)
}
})
}
},
methods: {
// 高亮选项卡
changeLogin(i) {
this.login_type = i;
if (i) {
this.a0 = 0;
this.a1 = 1;
} else {
this.a0 = 1;
this.a1 = 0;
}
},
loginAction() {
if (!this.username || !this.password) {
return
}
this.$axios({
url: this.$settings.base_url + '/user/login/',
method: 'post',
data: {
'username': this.username,
'password': this.password,
'is_remeber': this.remeber
}
}).then((response) => {
if (response.data.status == 0) {
let token = response.data.results.token;
let username = response.data.results.username;
// 判断用户是否要记住密码
if (this.remember) { // 记住密码
this.$cookies.set('token',token,-1);
this.$cookies.set('username',username,-1);
} else { /// 没记住密码
this.$cookies.set('token',token,"0");
this.$cookies.set('username',username,"0");
}
this.$alert("欢迎回来!", "登录成功!", {
confirmButtonText: '确定',
callback: () => {
// 登录成功去主页
this.$router.push("/");
}
})
} else {
this.username = '';
this.password = '';
}
}).catch(() => {
this.$alert("检查账号密码!", "登录失败!", {
confirmButtonText: '确定',
callback: () => {
this.username = '';
this.password = '';
}
});
})
},
send_sms() {
// 发送短信
if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
this.$message({
message: "对不起!手机号码格式有误!"
});
return false;
}
// 判断是否在60s内发送过短信
if (this.is_send) {
this.$message({
message: "对不起,不能频繁发送短信验证!"
});
return false;
}
// 请求发送短信
this.$axios({
url: this.$settings.base_url + '/user/sms/',
method: 'post',
data: {
mobile: this.mobile
}
}).then(response => {
let msg = response.data.msg;
this.$message({
message: msg,
});
if (msg === '短信发送失败') return;
// 修改短信的发送状态
this.is_send = true;
// 设置间隔时间60s
let sms_interval_time = 60;
// 设置短信发送间隔倒计时,.60s后把is_send改成false
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval_tips = "获取验证码";
this.is_send = false; // 重新回复点击发送功能的条件
} else {
sms_interval_time -= 1;
this.sms_interval_tips = `${sms_interval_time}秒后再次获取`;
}
}, 1000);
}).catch(error => {
this.$message({
message: error.response.data.result,
})
});
},
loginMobile() {
// 注册信息提交
if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
this.$message({
message: "对不起!手机号码格式有误!"
});
return false;
}
if (this.sms.length < 1) {
this.$message({
message: "短信验证码不能为空!"
});
return false;
}
this.$axios({
url: this.$settings.base_url + '/user/login/',
method: 'post',
data: {
username: this.mobile,
code: this.sms,
is_remeber: this.remember,
}
}).then(response => {
let _this = this;
let status = response.data.status;
let msg = response.data.msg;
if (status == 0) {
// cookie存储token,保存登录状态
let token = response.data.results.token;
let username = response.data.results.username;
console.log(this.remember);
if (this.remember) { // 记住密码
this.$cookies.set('token',token,-1);
this.$cookies.set('username',username,-1);
} else { /// 没记住密码
this.$cookies.set('token',token,"0");
this.$cookies.set('username',username,"0");
}
_this.$message({
message: '登录成功',
duration: 1000,
onClose() {
// // 保存登录状态
// sessionStorage.token = token;
// sessionStorage.username = response.data.results.username;
// sessionStorage.mobile = response.data.results.mobile;
// 跳转到主页
_this.$router.push('/');
}
});
}
else {
_this.mobile = '';
_this.sms = '';
_this.$message({
message: msg,
});
}
}).catch(error => {
this.mobile = '';
this.sms = '';
this.$message({
message: error.response.data.result
});
})
},
},
};
</script>
<template>
<div class="header-box">
<div class="header">
<div class="content">
<!-- 图标-->
<div class="logo full-left">
<router-link to="/"><img @click="jump('/')" src="@/assets/img/logo.svg" alt=""></router-link>
</div>
<!-- 课程序列-->
<ul class="nav full-left">
<li><span @click="jump('/course')" :class="this_nav=='/course'?'this':''">免费课</span></li>
<li><span @click="jump('/light-course')" :class="this_nav=='/light-course'?'this':''">轻课</span></li>
<li><span>学位课</span></li>
<li><span>题库</span></li>
<li><span>老男孩教育</span></li>
</ul>
<!-- 购物车以及登录注册-->
<div class="login-bar full-right">
<!-- 购物车-->
<div class="shop-cart full-left">
<img src="@/assets/img/cart.svg" alt="">
<span><router-link to="/cart">购物车</router-link></span>
</div>
<!-- 登录注册-->
<div class="login-box full-left">
<div v-if="!is_login">
<router-link to="/login">登录</router-link>
|
<router-link to="/register">注册</router-link>
</div>
<div v-else>
<router-link to="/user">{{ username }}</router-link>
|
<span @click="logoutAction">注销</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Header",
data() {
return {
this_nav: "",
is_login:"",
username:"",
}
},
created() {
this.this_nav = localStorage.this_nav;
this.this_nav = localStorage.this_nav;
this.is_login = this.$cookies.get('token');
this.username = this.$cookies.get('username');
},
methods: {
jump(location) {
// 改变永久仓库的值
localStorage.this_nav = location;
// vue-router除了提供router-link标签跳转页面以外,还提供了 js跳转的方式
this.$router.push(location);
},
logoutAction() {
this.is_login = false;
this.username = '';
this.$cookies.remove('token');
this.$cookies.remove('username');
}
}
}
</script>