Token
- 服务端会话技术
- 理解为自定义的Session,但是由于sessiom有缺陷,因为依赖于cookie,cookie依赖于浏览器(有的浏览器不支持cookie)
- **如果Web页面开发中,使用起来和Session基本一致**
- **如果使用在移动端或客户端开发中,通常以Json形式传输**,需要移动端自己存储Token,需要获取Token关联数据的时候,主动传递Token
Cookie和Session,Token对比
- Cookie使用更简洁,服务器压力更小,数据不是很安全
- Session服务器要维护Session,相对安全
- Token拥有Session的所有优点,自己维护略微麻烦,但支持更多的终端,不只是浏览器,也有手机客户端,或者桌面应用开发,这些本身不支持cookie,一旦不支持cookie所有的会话技术就挂了,所以产生了token
TOKEN实现了不依赖于cookie,来识别客户端,token在计算机身份认证中是令牌的意思,我们学习的是会话令牌,交互会话中唯一身份标识符。
实践:token实现用户登录
新建models:
from django.db import models
class Student(models.Model):
s_name = models.CharField(max_length=16, unique=True)
s_password = models.CharField(max_length=128)
# 这里加token模型,因为还没有学缓存,按道理token应该加在缓存之中。
s_token = models.CharField(max_length=256)
迁移模型至数据库
新建模板student_register.html用来做学生注册界面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>studentRegister</title>
</head>
<body>
<form action="{% url 'two:register' %}" method="post">
<span>用户名</span><input type="text" name="username" placeholder="请输入用户名">
<br>
<span>密码:</span><input type="text" name="password" placeholder="请输入银行卡密码">
<br>
<button>注册</button>
</form>
</body>
</html>
- span标签是超文本标记语言(HTML)的行内标签,被用来组合文档中的行内元素。
表单能够包含 input 元素,比如文本字段、复选框、单选框、提交按钮等等。
表单还可以包含 menus、textarea、fieldset、legend 和 label 元素。
表单用于向服务器传输数据。
- br换行符
新建url
url('^register', views.register, name='register')
新建views:
def register(request):
if request.method =='GET':
# 用来响应登陆界面
return render(request, 'student_register.html')
elif request.method == 'POST':
# 用来接收客户端中的用户名密码
username = request.POST.get('username')
password = request.POST.get('password')
try:
# 用来在数据库中存储刚刚接收过来的用户名与密码
student = Student() # 实例化模型
student.s_name = username # 赋值给模型
student.s_password = password
student.save() # 保存数据至数据库
except Exception as e:
# 只要发生了错误,重定向回到注册界面
return redirect(reverse('two:register'))
return HttpResponse('注册成功')
访问,点击注册:
返回注册成功
这时我们继续注册同样的用户名与密码
我们会发现,点击注册,仍然是注册界面
说明,用户名重复,注册发生了错误,进行了重定向
注册界面完成,接下来我们添加登录界面
url:
url('^studentlogin', views.student_login, name='studentlogin'),
新建student_login.html作为登录页面
views:
def student_login(request):
if request.method == 'GET':
return render(request, 'student_login.html')
elif request.method == 'POST':
# 拿到用户名密码
username = request.POST.get('username')
password = request.POST.get('password')
# 获取ip地址
# 在数据库中比对用户名和密码
students = Student.objects.filter(s_name=username).filter(s_password=password)
# 由于用户名唯一,只要匹配上就只有一个结果
if students.exists():
student = students.first()
# 用户名密码匹配正确的用户端后,生成token
ip = request.META.get('REMOTE_ADDR')
token = generate_token(ip, username)
# 将生成的token,保存到对应用户名的数据库中的s_token字段中
student.s_token = token
student.save()
# 将自定义的token利用cookie返回到客户端中,也可以用jsonresponse进行返回
response = HttpResponse('登陆成功')
response.set_cookie('token', token)
return response
# 如果用户不存在,重定向
return redirect(reverse('two:student_login'))
# 由于token要求唯一,在python 3.6以上有专门生成唯一token的方法,
# 我们也可以手动写函数生成唯一token
def generate_token(ip, username):
# 时间,ctime返回的时间是字符串型
c_time = time.ctime()
# 由于并发量,两个人访问时间相同,我们还传入ip地址参数
r = username
# 将time,随机数,ip地址组合起来md5加密
return hashlib.new('md5', (ip + c_time + r).encode('utf-8')).hexdigest()
hashlib.new(
`'md5',
(ip + c_time + r).encode('utf-8'
))`是哈希对象
.hexdigest()是获取字符串
接着我们尝试登录刚刚注册的用户名:成功
而当我们错误登录时,会发现重定向回原来的界面
这时候我们新建url当作登录成功的个人中心:
url('^studentmine/', views.student_mine, name='studentmine'),
views:
# 显示个人中心
def student_mine(request):
# 根据cookie查找到个人用户信息
token = request.COOKIES.get('token')
try:
student = Student.objects.get(s_token=token)
except Exception as e:
return redirect(reverse('two:studentlogin'))
# 登陆正常
return HttpResponse(student.s_name)
访问,成功返回用户名
这个实践类似于我们手动将session模拟了出来,但这还是依赖于cookie
假如我们的客户端是移动端,没有cookie,我们可以采用jsonResponse来返回token
views修改如下:
def student_login(request):
if request.method == 'GET':
return render(request, 'student_login.html')
elif request.method == 'POST':
# 拿到用户名密码
username = request.POST.get('username')
password = request.POST.get('password')
# 获取ip地址
# 在数据库中比对用户名和密码
students = Student.objects.filter(s_name=username).filter(s_password=password)
# 由于用户名唯一,只要匹配上就只有一个结果
if students.exists():
student = students.first()
# 用户名密码匹配正确的用户端后,生成token
ip = request.META.get('REMOTE_ADDR')
token = generate_token(ip, username)
# 将生成的token,保存到对应用户名的数据库中的s_token字段中
student.s_token = token
student.save()
# 移动端 服务器将token利用responsed返回到客户端中
data = {
'status': 200,
'msg': 'login success',
'token': token
}
return JsonResponse(data=data)
# 移动端用户登陆失败返参数
data = {
'status': 800,
'msg': 'verify fail'
}
return JsonResponse(data=data)
# 由于token要求唯一,在python 3.6以上有专门生成唯一token的方法,
# 我们也可以手动写函数生成唯一token
def generate_token(ip, username):
# 时间,ctime返回的时间是字符串型
c_time = time.ctime()
# 由于并发量,两个人访问时间相同,我们还传入ip地址参数
r = username
# 将time,随机数,ip地址组合起来md5加密
return hashlib.new('md5', (ip + c_time + r).encode('utf-8')).hexdigest()
# 显示个人中心
def student_mine(request):
# 服务器从移动端获取token
token = request.GET.get('token')
try:
student = Student.objects.get(s_token=token)
except Exception as e:
return redirect(reverse('two:studentlogin'))
# 登陆正常,移动端
data = {
'msg': 'ok',
'status': 200,
'data': {
'username':student.s_name
}
}
return JsonResponse(data=data)
接着我们用pycharm模拟移动端请求post
pycharm自带了测试工具
然而有坑,返回失败,我们还是用网页测试吧
然后访问studentmine/?token=
我们可以看到返回成功,这样就可以交给移动端的api.
此处评论已关闭