第四章:Token的使用

1.账号密码登录获取token

app/models/user.py

from . import db
from .base import Base
from werkzeug.security import generate_password_hash, check_password_hash
from app.libs.error_code import My_notfound, AuthFail

class User(Base):

    ......
    ......

    @staticmethod   # 登录验证用户是否存在,密码是否一致
    def vertify_user_password(account, password):
        user = User.query.filter_by(email=account).first()
        if not user:
            raise My_notfound()
        if not user.check_pwd(password):
            raise AuthFail()
        return {"user": user}

app/v1/token.py

# -*- coding: utf-8 -*-
# @Author: Lai
from app.libs.red_print import Red_Print
from flask import request, current_app, jsonify
from app.validators.forms import ClientForm
from app.libs.enums import ClientTypeEnum
from app.models.user import User
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

api = Red_Print('token')

# 登录并获取令牌
@api.route('', methods=['POST'])
def get_token():
    data = request.json
    form = ClientForm(data=data).validate_for_api()
    promise = {
        ClientTypeEnum.USER_EMAIL: __vertify_cate_email,
        ClientTypeEnum.USER_MOBILE: __vertify_cate_mobile,
        ClientTypeEnum.USER_MINA: __vertify_cate_mina,
    }
    identity = promise[form.type.data](form)
    user = identity['user']
    uid = user.id
    int_type = form.type.data.value
    scope = ''
    token = generate_auth_token(uid, int_type, scope).decode("utf8")
    return jsonify({"token": token})


# 生成令牌
def generate_auth_token(uid, int_type, scope=None, expiration=7200):
    s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration)
    data_dict = dict(
        uid=uid,
        int_type=int_type,
        scope=''
    )
    token_data = s.dumps(data_dict)
    return token_data


# PC验证
def __vertify_cate_email(form):
    result = User.vertify_user_password(form.account.data, form.password.data)
    return result

# 移动端验证
def __vertify_cate_mobile():
    pass

# 小程序验证
def __vertify_cate_mina():
    pass

2.带着token访问资源

用到flask_httpauth模块

app/libs/auth_token.py

# -*- coding: utf-8 -*-
# @Author: Lai

from flask_httpauth import HTTPBasicAuth
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import BadSignature, SignatureExpired
from flask import current_app, g, request
from app.libs.error_code import AuthFail, My_notfound
from collections import namedtuple
from base64 import b64decode
from functools import wraps

User = namedtuple('User', ['uid','int_type','scope'])
auth = HTTPBasicAuth()

@auth.verify_password
def vertify_password(account_or_token, password):
    # 验证token
    user = checked_token(account_or_token)
    if not user:
        return False
    else:
        g.user = user   # 使用g防止超权
        return True


def checked_token(token):
    s = Serializer(current_app.config['SECRET_KEY'])
    try:
        data_dict = s.loads(token.encode('utf8'))
    except SignatureExpired as e:
        raise AuthFail(msg='token is expired')  # token超时
    except BadSignature as e:
        raise AuthFail(msg='token is valid')    # token无效
    uid = data_dict['uid']
    int_type = data_dict['int_type']
    scope = data_dict['scope']
    user = User(uid, int_type, scope)
    return user

app/v1/user.py

# -*- coding: utf-8 -*-
# @Author: Lai
from flask import g

from app.libs.red_print import Red_Print
from app.libs.auth_token import auth, decorator
from flask import jsonify

api = Red_Print('user')

@api.route('', methods=['POST'])
@auth.login_required  # 此处验证工作交由app/libs/auth_token.py中的vertify_password方法完成
def get_user():
    user = g.user
    return jsonify(user)

3.自定义验证装饰器

app/libs/auth_token.py

...

from base64 import b64decode
from functools import wraps


def checked_token(token):
    ...
    ...

def decorator(func):
    @wraps(func)
    def inner(*args, **kwargs):
        print(request.headers)
        _b64token = request.headers.get('Authorization')   # Authorization: Basic ZXlKaGJHY2lPaUpJVXpJMU5pxxx
        b64token = _b64token.split(' ')[1]   # 去除 Basic
        token = b64decode(b64token)         # 解除base64加密
        token = token.decode('utf8').replace(":","")  # 把token 转成字符串(unicode)并去除:号
        user = checked_token(token)
        if not user:
            raise My_notfound()
        else:
            g.user = user
        return func(*args, **kwargs)
    return inner

app/v1/user.py

# -*- coding: utf-8 -*-
# @Author: Lai
from flask import g

from app.libs.red_print import Red_Print
from app.libs.auth_token import decorator
from flask import jsonify

api = Red_Print('user')

@api.route('', methods=['POST'])
@decorator
def get_user():
    user = g.user
    return jsonify(user)

猜你喜欢

转载自blog.csdn.net/lilied001/article/details/80794303