登录、认证、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 ...
随机推荐
- css两种常用的不定宽高的水平垂直居中方法,记住它,不再为样式发愁
css 几种常用的简单容易记住的水平垂直居中方法 前言 正文 第一种方法 第二种方法 结束语 前言 我们在设计网页时,会大量的运用到水平垂直居中,如果知道元素的宽高,那水平垂直居中是很简单的,无非是用 ...
- javaWeb项目之图书管理系统(附视频讲解)
视频播放地址:javaWeb图书系统 本系统为"Swing项目之图书管理系统"(此源码已共享)的Web版,网页框架用采用EasyUI 数据库为MysqL,写Web项目摒弃了火狐浏览 ...
- 原生js实现 vue的数据双向绑定
原生js实现一个简单的vue的数据双向绑定 vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时 ...
- 【转】Windows10删除文件时却提示文件不存在的解决方案
Windows10系统使用一段时间后用户都会定期进行删除清理系统垃圾,减少系统盘的容量占用,但在删除的过程中许多用户都有可能遇到无法删除的情况,如下为删除文件时却提示文件不存在的解决方案. 1.新建一 ...
- better-scroll实现滚动
通过better-scroll这个插件实现微信好友滚动列表 安装better-scroll npm i better-scroll 初始化better-scroll //better-scroll ...
- Hadoop 2.6.1 集群安装配置教程
集群环境: 192.168.56.10 master 192.168.56.11 slave1 192.168.56.12 slave2 下载安装包/拷贝安装包 # 存放路径: cd /usr/loc ...
- 扫盲--CRM系统和ERP系统的区别
企业规模在逐步扩大的时候,为了提高生产和管理的效率,经常需要用到相关管理软件.很多企业管理者在选择管理软件的时候犯了难,面对CRM系统和ERP系统不知如何选择无法下手.那么,CRM和ERP的区别是什么 ...
- elementUI table怎么实现点击上移下移
其实炒鸡简单... <el-table :data='tableData' > ... ... <el-table-column label="操作" al ...
- jsp页面关于isELIgnored="false",页面无法解析数据问题
问题: 首先确定所取的集合里面是否有值,如果没有先检查集合 如果有,就再jsp页面头部添加: isELIgnored="false" 具体如下: <%@ page langu ...
- Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案
本文为霍格沃兹测试学院学员学习笔记. Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能.装饰器本质是一种返回值也是函数的函数,可以称之为“函数的函数”. ...