登录、认证、token处理、前台cookie存储token
免费课程相关表设计
models的设计
from django.contrib.contenttypes.fields import GenericRelation
class Course(models.Model):
name = models.CharField(verbose_name="课程名", max_length=32)
title = models.CharField(verbose_name="课程简介", max_length=128, null=True, blank=True)
# 存放media文件夹下图片的相对路径:eg: media/python入门.jpeg
image = models.CharField(verbose_name="海报", max_length=64, null=True, blank=True)
# 用户连表查询,不会在数据库中产生字段
price_policy = GenericRelation(to='PricePolicy') def __str__(self):
return self.name
class Meta:
verbose_name_plural = "免费课程" class CourseDetail(models.Model):
level = models.IntegerField(default=1, choices=((0, '初级'), (1, "中级"), (2, "高级")))
movie_url = models.CharField(max_length=64)
info = models.TextField()
course = models.OneToOneField(to='Course', null=True, on_delete=models.SET_NULL, db_constraint=False)
teacher = models.OneToOneField(to='Teacher', null=True, on_delete=models.SET_NULL, db_constraint=False) def __str__(self):
return self.course.name + '的详情'
class Meta:
verbose_name_plural = "免费课程详情" class Teacher(models.Model):
name = models.CharField(max_length=32)
info = models.TextField()
image = models.CharField(max_length=64)
level = models.IntegerField(default=0, choices=((0, '初级讲师'), (1, "金牌讲师"), (2, "特约讲师")))
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "讲师" class DegreeCourse(models.Model):
name = models.CharField(max_length=32)
price_policy = GenericRelation(to='PricePolicy')
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "学位课程" from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
class PricePolicy(models.Model):
day = models.IntegerField()
price = models.CharField(max_length=8)
object_id = models.IntegerField()
content_type = models.ForeignKey(to=ContentType, null=True)
# 改操作只用于ContentType连表查询,不会产生表字段, 就是关联课程表的对象
model_obj = GenericForeignKey() def __str__(self):
return "%s:(%s天 ¥:%s)" % (self.model_obj.name, self.day, self.price) class Meta:
verbose_name_plural = "价格策略"
前台路由与页面
APP.vue组件
<div id="nav">
<router-link to="/">主页</router-link>
|
<router-link to="/login">登录</router-link>
|
<router-link to="/course">免费课程</router-link>
|
<!-- 在页面中转跳路由传递参数, 传递了params参数,this.$router.params可以拿到这个参数字典 -->
<!--<router-link :to="{'name': 'degree-course', 'params': {'id': 1, 'name': 'owen'}}">学位课程</router-link>-->
<router-link :to="{'name': 'degree-course'}">学位课程</router-link>
</div>
router.js路由配置
# 在views文件夹中建立对应的组件
{
path: '/login',
name: 'login',
component: () => import('./views/Login.vue')
},
{
path: '/course',
name: 'course',
component: () => import('./views/Course.vue')
},
{
path: '/degree-course',
name: 'degree-course',
component: () => import('./views/DegreeCourse.vue')
},
{
path: '/course-detail',
name: 'course-detail',
component: () => import('./views/CourseDetail.vue')
}
项目开发视图与响应的二次封装
响应
# api.utils.py
class ApiResponse:
def __init__(self, status=0, message='ok'):
self.status = status
self.message = message
# 要返回给前台的api字典
@property
def api_dic(self):
return self.__dict__
视图
# 在api应用文件夹下创建包views
# 1.分文件管理不同的视图类,视图类继承ModelViewSet管理一系列视图函数
# 2.在__ini__文件中统一管理到 视图类 # __init__.py
from .Course import CourseView # views文件夹/Course文件/CourseView
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from api.utils import ApiResponse
from api import models, objectjson class CourseView(ModelViewSet):
def get(self, request, *args, **kwargs):
api_response = ApiResponse()
course_list = models.Course.objects.all()
course_data = objectjson.CourseJson(course_list, many=True).data
api_response.results = course_data
return Response(api_response.api_dic)
免费课程首页展示
main.js配置后台请求根路径
// 后台根接口
Vue.prototype.$base_api = 'http://127.0.0.1:8000/';
views/Course.vue
<template>
<div class="course">
<h2>免费课程</h2>
<!--course_list是从后台获取,有多少条数据,就会渲染多少个子组件CourseView-->
<div v-for="(course,i) in course_list" :key="course.name+i">
<!--通过绑定属性的方式,将course传给属性course,在组件内部提高props=['course']拿到父组件的数据-->
<CourseView :course="course"></CourseView>
</div>
</div>
</template> <script>
import CourseView from "../components/CourseView"; export default {
name: "Course",
data: function () {
return {
course_list: []
}
},
components: {
CourseView: CourseView,
},
mounted: function () {
let _this = this;
this.$ajax({
method: 'get',
url: this.$base_api + 'courses/',
}).then(function (response) {
_this.course_list = response.data.results
})
}
}
</script> <style scoped> </style>
components/CourseView.vue
<template>
<div class="course-view">
<div class="box">
<h3 @click="goDetail(course.id)">{{course.name }}</h3>
<p>{{ course.title }}</p>
</div>
<img @click="goDetail(course.id)" :src="$base_api + course.image" alt="">
</div>
</template> <script>
export default {
name: "CourseView",
props: ['course'],
methods: {
goDetail: function (pk) {
//前往详情页,在方法中,router如何完成路由的跳转
this.$router.push('/course-detail');
// 业务逻辑下,路由转跳携带参数
this.$router.course_id = pk;
window.console.log(pk)
}
}
}
</script> <style scoped>
.course-view {
padding: 0 200px;
margin: 25px 0;
} .course-view .box {
float: left;
width: 380px;
} .course-view img {
width: 400px;
float: left;
} .course-view:after {
display: block;
clear: both;
content: '';
}
</style>
views/Course.vue/CourseDetail.vue
<template>
<div class="course-detail">
<h2>免费课程详情</h2>
<p>{{ detail }}</p>
</div>
</template> <script>
export default {
name: "CourseDetail",
data: function () {
return {
detail: {},
}
},
mounted: function () {
let _this = this;
this.$ajax({
method: 'get',
url: this.$base_api + 'course/' + this.$router.course_id + '/',
}).then(function (response) {
window.console.log(response);
_this.detail = response.data.results;
})
}
}
</script> <style scoped> </style>
前后台登录认证
时区国际化settings.py
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False
models.py
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32) class UserToken(models.Model):
token = models.CharField(max_length=64)
user = models.OneToOneField(to='User', null=True, on_delete=models.SET_NULL, db_constraint=False)
update_time = models.DateTimeField(auto_now=True)
failed_time = models.FloatField(default=10)
objectson.py
class UserJson(serializers.ModelSerializer):
class Meta:
model = models.User
fields = '__all__' class UserTokenJson(serializers.ModelSerializer):
class Meta:
model = models.UserToken
fields = '__all__'
auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed from api import models class LoginAuthenticate(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
result = models.UserToken.objects.filter(token=token).first() # type:models.UserToken
if result:
# 最近一次登录的时间
before_time = result.update_time
# 过期时长秒数
failed_time = result.failed_time
# 当你时间往前推演到过期的时长前的最后时刻
import datetime
time_difference = datetime.datetime.now() - datetime.timedelta(seconds=failed_time)
import time
# 存在时区问题,通过国际化解决
before_time_stamp = time.mktime(before_time.timetuple()) # 拿到时间戳
time_difference_stamp = time.mktime(time_difference.timetuple())
if before_time_stamp >= time_difference_stamp:
return result.user, token
raise AuthenticationFailed('登录过期')
else:
raise AuthenticationFailed('认证失败')
前台安装操作cookie的模块
<template>
<div class="login">
<h2>登录页面</h2>
<div class="form">
<el-form :model="form" label-width="100px">
<el-form-item label="用户名">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" v-model="form.password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template> <script>
export default {
name: "Login",
data: function () {
return {
form: {
username: '',
password: '',
}
}
},
methods: {
onSubmit() {
// window.console.log('aaaa');
let _this = this;
this.$ajax({
method: 'post',
url: this.$base_api + 'login/',
data: {
username: this.form.username,
password: this.form.password
}
}).then(function (response) {
window.console.log(response);
let token = response.data.token;
_this.$cookie.set('token', token);
_this.$router.push('/')
})
}
}
}
</script> <style scoped> </style>
router.js
{
path: '/login',
name: 'login',
component: () => import('./views/Login.vue')
},
登录、认证、token处理、前台cookie存储token的更多相关文章
- app与php后台接口登录认证、验证(seesion和token)
简要:随着电商的不断发展,APP也层次不穷,随着科技的发展主要登录形式(微信.QQ.账号/密码):为此向大家分享一下"app与php后台接口登录认证.验证"想法和做法:希望能够帮助 ...
- 如何区别cookie和token?---测试cookie和token接口时先看。
cookie 是什么? cookie--------------在浏览器中的长相?火狐浏览器 ----------------------------------------------------- ...
- cookie session token详解
cookie session token详解 转自:http://www.cnblogs.com/moyand/ 发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, ...
- Cookie、Token与Session介绍(非原创)
文章大纲 一.Cookie介绍二.Token介绍三.Session介绍四.Token.Cookie与Session比较五.参考文章 一.Cookie介绍 1. Cookie是什么 cookie机制 ...
- cookie,session,token介绍
本文目录 发展史 Cookie Session Token 回到目录 发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档 ...
- cookie,session,token的理解
Get POST 区别异同点 淘宝token的 理解 过程算法 防止伪造请求 伪造相对难 简单发展史 登录的操作: 哪些人往自己的购物车中放商品, 也就是说我必须把每个人区分开,这就是一个 ...
- session、cookie、token
各自应用场景考虑session.token.cookie是不是有各自的应用场景,比如传统项目适合用session和cookie单页应用适合用token分布式适合用token等等 token如果非要选择 ...
- 基于JWT的Token登录认证(一)
1.JWT简介 JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案. session登录认证方案:用户从客户端传递用户名.密码等信息,服务端认证后将信息存储在session中 ...
- 权限认证 cookie VS token
权限认证 cookie VS token 我前公司的应用都是 token 授权的,现公司都是维护一个 session 确认登录状态的.那么我在这掰扯掰扯这两种权限认证的方方面面. 工作流程 先说 co ...
随机推荐
- go module 获取码云私有仓库代码
因为码云免费组织有5人限制,其他人想获得代码 只能通过别的方式 go mod 底层使用的git 获取代码, 所以首先解决如何通过git clone代码 思路为通过ssh密钥的方式获取 首先在码云仓库部 ...
- JavaScript学习系列博客_11_JavaScript中的for语句
for循环 - 语法: for(①初始化表达式 ; ②条件表达式 ; ④更新表达式){ ③语句... } - 执行流程: 首先执行①初始化表达式,初始化一个变量,(这里只会执行一次) 然后对②条件表达 ...
- 12. oracle 常用函数
一.字符函数字符函数是oracle中最常用的函数,我们来看看有哪些字符函数:lower(char):将字符串转化为小写的格式.upper(char):将字符串转化为大写的格式.length(char) ...
- centos7 + nginx+django 运行环境
.easy_install和pip都是用来下载安装Python一个公共资源库PyPI的相关资源包的 首先安装easy_install 下载地址:https://pypi.python.org/pypi ...
- 深入理解k8s中的访问控制(认证、鉴权、审计)流程
Kubernetes自身并没有用户管理能力,无法像操作Pod一样,通过API的方式创建/删除一个用户实例,也无法在etcd中找到用户对应的存储对象. 在Kubernetes的访问控制流程中,用户模型是 ...
- 计算机网络-网络层(6)ICMP协议
互联网控制报文协议(ICMP,Internet Control Message Protocol),被主机和路由器用来彼此沟通网络层的信息 ICMP报文是承载在IP分组中的,即lCMP报文是作为IP有 ...
- Eligibility Traces and Plasticity on Behavioral Time Scales: Experimental Support of neoHebbian Three-Factor Learning Rules
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Abstract 大多数基本行为,如移动手臂抓住物体或走进隔壁房间探索博物馆,都是在几秒钟的时间尺度上进化的:相反,神经元动作电位则是在几 ...
- 牛客网PAT练兵场-打印沙漏
题目地址:https://www.nowcoder.com/pat/6/problem/4053 题意:模拟题 /** * Copyright(c) * All rights reserved. * ...
- 玩转Spring——Spring事务
事务的概念:多个sql 操作 要么都成功 要么都失败 ACID特性:原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生.一致性(Consisten ...
- ms-data(转载)
转载:https://www.cnblogs.com/zll-52011/p/10960905.html 1.从美国矿物数据库下载矿物CIF(有晶格) 2.晶胞CIF导入MS 3.选择display ...