10.用户登录——什么是token、生成token、token获取用户信息免密登录、登录装饰器

1.为什么需要登录认证

换句话来说,为什么需要session、cookie和token
这个认证信息需要的原因,就是比如说我们今天使用淘宝点击添加购物车,然后就需要一个请求,但是发送这个请求之前,需要验证是哪个用户所登录,所以就需要一个类似通行码的东西去标识已登录。所以就存在了这些东西是吧?

2.session、cookie和token的区别

这个session的话,首先出现了他,他存储再服务端,但是服务器压力就很大,如果出现了损坏,大家都得重新登录,所以出现了cookie。cookie是存储在客户端的,但是如果web服务器做了负载均衡,下一个操作请求到了另一个服务器session就会丢失。就是无法跨设备免密登录。然后就出现了token,token是随着登录成功一起生成保存在客户端,客户端每次访问的话都是携带者token去访问服务端,所以就更加好

3.实操

在这里插入图片描述
当我们登录成功以后,并没有一个相应的标识,做出特殊的处理。这里,我们登录成功以后,就需要一个通行证的东西,去标识我们已经登录。这里可以是session、token标识。本次,我们将使用jwt(JSON WEB TOKEN)
jwt是用于生成token
jwt官网:jwt.io
jwt使用方法:github

4.用户登录_生成Token并响应——使用jwt

2.1下载jwt

pip install pyjwt

2.2 代码展示

# forum/handler/UserHandler.py
from forum.wtforms import UserForm,LoginUserForm
from forum import manager
from forum.models import UserModel
from uuid import uuid4
from forum.handler.BaseHandler import BaseHandler
from forum.utils.email_utils import send_mail
from forum.utils.redis_utils import *
from random import randint
import jwt
from config import secret,email
# 登录接口
class LoginHandler(BaseHandler):
    async def post(self):
        # 记录登录信息
        print("1234")
        rs_data = {}
        # 获取表单数据
        user_form = LoginUserForm(self.request.arguments)
        # 验证是否符合form表单输入的规则
        if user_form.validate():
            try:
                # 数据库中获取
                user = await manager.get(UserModel, email=user_form.email.data, password=user_form.password.data)
                # 获取到了,登录成功
                print(user_form.email.data)
                print(user_form.password.data)
                rs_data['code'] =200
                rs_data['msg'] = '登录成功!!!'
                payload = {
                    'email': user_form.email.data
                }
                # 生成一个用户信息(加密)token,返回给前端,下一次访问时,携带用户信息回来即可
                token = jwt.encode(payload, secret, algorithm='HS256')# 参数含义:加密谁,加密的密码(盐)、加密的算法
                rs_data['token'] = token
            except Exception as e: 
                # 获取不到,登录失败
                rs_data['code'] = 401
                rs_data['msg'] = '用户名或密码错误'
        else:
            rs_data['code'] = 401
            rs_data['msg'] = '用户名不符合规范'
            for f in user_form.errors:
                print(user_form.errors)
                rs_data[f] = user_form.errors[f][0]
        self.finish(rs_data)

2.3 登录完成效果展示

在这里插入图片描述

5.用户登录_token获取用户信息

5.1概述

当我们登录完成以后,前端并没有展示出登录成功的状态。这里我们需要一个接口,获取用户登录成功的信息,获取他的登录通行证token。从token中解析是否存在数据email,如果存在则登录成功。(token是随着登录时一起产生在服务端的,存放在请求头中)

5.2代码展示

5.2.1转换用户信息

# forum/models.py
# 用于创建数据表模型
from peewee import *
from forum import database
from datetime import datetime
# 创建基类:减少重复代码
class BaseModel(Model):
    create_time = DateTimeField(default = datetime.now)
    # 创建函数,用于返回用户的信息位字典形式
    def to_json(self) -> dict:
        r = {}
        for k in self.__data__.keys():
            # 判断数据是否是create_time(时间不是字符串)
            if k == 'create_time':
                r[k] = str(getattr(self,k))
            else:
                r[k] = getattr(self,k)
        return r 

5.2.2 token获取用户信息接口实现——免密登录

# forum/handler/UserHandler.py
from forum.wtforms import UserForm,LoginUserForm
from forum import manager
from forum.models import UserModel
from uuid import uuid4
from forum.handler.BaseHandler import BaseHandler
from forum.utils.email_utils import send_mail
from forum.utils.redis_utils import *
from random import randint
import jwt
from config import secret,email
       
# token获取用户信息接口实现——免密登录
class GetUserHandler(BaseHandler):
    async def get(self):
        rs_data = {}
        # 获取token
        token = self.request.headers.get('token')
        # 从token值解析出email
        payload = jwt.decode(token, secret, algorithms=['HS256'])
        if payload:
            # 通过email查询数据
            email = payload.get('email')
            user = await manager.get(UserModel, email=email)
            # 判断是否存在这个用户
            if user:
                # 有数据,将用户信息返回给前端
                rs_data['code'] = 200
                rs_data['msg'] = '获取用户成功!!!'
                rs_data['user'] = user.to_json()
                # 没有数据,没有登录
            else:
                rs_data['code'] = 500
                rs_data['msg'] = 'toekn错误!!!'
        else:
            rs_data['code'] = 500
            rs_data['msg'] = '请登录后再操作!!!'
        self.finish(rs_data)

5.3 效果展示

shengc

6.装饰器验证是否登录

装饰器

# forum/wtforms.py
# 完整注册(给t_user表)增加数据之前的数据验证
from wtforms_tornado import Form
from wtforms.fields import StringField
from wtforms.fields.simple import HiddenField
from wtforms.validators import DataRequired, Length

# 对t_user的数据验证
class UserForm(Form):
    id = HiddenField()
    email = StringField('账号', validators=[DataRequired(message='请填写合法的邮箱地址'),Length(min=5, max=20, message='请输入5-20长度的邮箱')])
    nick_name = StringField('昵称', validators=[Length(min=2, max=10, message='请输入2-10长度的昵称')])
    password = StringField('密码', validators=[Length(min=2, message='请输入2以上长度的密码')])
    signature = StringField('签名')
    pic = StringField('头像')

# 对登录的数据验证
class LoginUserForm(Form):
    id = HiddenField()
    email = StringField('账号', validators=[DataRequired(message='请填写合法的邮箱地址'),Length(min=5, max=20, message='请输入5-20长度的邮箱')])
    nick_name = StringField('昵称')
    password = StringField('密码', validators=[Length(min=2, message='请输入2以上长度的密码')])
    signature = StringField('签名')
    pic = StringField('头像')

优化免密登录

# forum/handler/UserHandler.py
from uuid import uuid4
from random import randint

import jwt

from forum.wtforms import UserForm,LoginUserForm
from forum import manager
from forum.models import UserModel
from forum.handler.BaseHandler import BaseHandler
from forum.utils.email_utils import send_mail
from forum.utils.redis_utils import *
from config import secret,email
from forum.decorators import login_required_async

# 调用wtforms做添加用户数据之前的数据表单验证
class AddUserHandler(BaseHandler):
    async def post(self):
        # 创建应该响应对象
        rs_data = {}
        # 接受请求的参数并封装到Form对象中
        user_form = UserForm(self.request.arguments)
        # 前端传递的验证码
        code = self.get_body_argument('code')
        # 后端的正确的验证码
        db_code = get_code(user_form.email.data)
        if code == db_code:
            if user_form.validate():
                # 从表单中获取email信息
                email = user_form.email.data
                try:
                    # 异步查询数据表信息
                    exist_user = await manager.get(UserModel,email = email)
                    if exist_user:
                        # 存在此用户,验证失败
                        rs_data['code'] = 500
                        rs_data['msg'] = '用户名已存在'
                except Exception as e:
                    # 验证成功
                    # 异步保存数据到数据库中
                    user_form.id.data = uuid4()
                    await manager.create(UserModel,**user_form.data)
                    rs_data['code'] = 200
                    rs_data['msg'] = '注册成功'
            else:
                # 验证失败
                rs_data['code'] = 500
                rs_data['msg'] = '注册失败'
                # 将验证失败的具体原因返回给rs_data,提示信息
                for f in user_form.errors:
                    rs_data[f] = user_form.errors[f][0]
        else:
            # 验证失败
                rs_data['code'] = 500
                rs_data['msg'] = '验证码错误'
        self.finish(rs_data)

    
# 发送邮件
class SendEmailHandler(BaseHandler):
    # 用于给定4位随机验证码
    def generate_code(self) -> int:
        return randint(1000,9999)
    # 发送邮件的接口
    def post(self):
        user_email = self.get_body_argument('email') # 获取前端form输入框中输入的邮箱
        code = self.generate_code()
        msg = f'您好,您正在使用{user_email}注册<CMS论坛项目>用户注册账号,您的验证码位{code},如果不是本人操作,请忽略'
        send_mail(email.get('uname'),email.get('pwd'),user_email,'<CMS论坛项目>用户注册',msg)
        save_code(user_email,code)

# 登录接口
class LoginHandler(BaseHandler):
    async def post(self):
        # 记录登录信息
        print("1234")
        rs_data = {}
        # 获取表单数据
        user_form = LoginUserForm(self.request.arguments)
        # 验证是否符合form表单输入的规则
        if user_form.validate():
            try:
                # 数据库中获取
                user = await manager.get(UserModel, email=user_form.email.data, password=user_form.password.data)
                # 获取到了,登录成功
                print(user_form.email.data)
                print(user_form.password.data)
                rs_data['code'] =200
                rs_data['msg'] = '登录成功!!!'
                payload = {
                    'email': user_form.email.data
                }
                # 生成一个用户信息(加密)token,返回给前端,下一次访问时,携带用户信息回来即可
                token = jwt.encode(payload, secret, algorithm='HS256')# 参数含义:加密谁,加密的密码(盐)、加密的算法
                rs_data['token'] = token
            except Exception as e: 
                # 获取不到,登录失败
                rs_data['code'] = 401
                rs_data['msg'] = '用户名或密码错误'
        else:
            rs_data['code'] = 401
            rs_data['msg'] = '用户名不符合规范'
            for f in user_form.errors:
                print(user_form.errors)
                rs_data[f] = user_form.errors[f][0]
        self.finish(rs_data)
        
# token获取用户信息接口实现——免密登录
class GetUserHandler(BaseHandler):
    @login_required_async
    async def get(self):
        rs_data = {}
        id = self._user_id
        try:
            user = await manager.get(UserModel,id=id)
            # 判断是否存在这个用户
            if user:
                # 有数据,将用户信息返回给前端
                rs_data['code'] = 200
                rs_data['msg'] = '获取用户成功!!!'
                rs_data['user'] = user.to_json()
        except Exception as e:
            rs_data['code'] = 500
            rs_data['msg'] = '请登录后再操作!!!'
        self.finish(rs_data)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想成为数据分析师的开发工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值