Flask-JWT-Extended 组件的使用方法


JWT

JWT(json web token): 头部、载荷、签名

头部 是一个  包含 加密算法和类型的 json字符串,  将字符串进行 base64 编码之后得到,一个 新的 字符串A

载荷 是一个json字符串, 包含 用户的身份信息, 将字符串进行 base64 编码之后得到,一个 新的 字符B, 不建议 存放用户的 敏感信息,因为 字符串可以被解密

将 字符串A 和字符串B用 . 链接, 得到一个新字符串,将新字符串使用密钥 和 第一部分声明的加密算法,进行加密,得到字符串C, 而C是不可逆的加C

最后,使用 . 链接 每一部分 字符串, 得到 字符串A.字符串B.字符串C
  • 服务器 只需要保留 密钥和算法,当 收到 客户端发送的 jwt后,使用 同样的算法和密钥进行 解密,解密成功,说明 用户是合法的;不成功,说明 用户身份被伪造

  • 本身避免session共享问题

  • 为了避免 csrf 攻击问题,将 jwt字符串存放到 请求头中

pip install flask-jwt-extended  # flask项目中使用jwt插件

流程

配置项

import datetime
import os


class Config(object):
   DEBUG = True  # 调试模式
   SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@127.0.0.1:3306/day08'  # 数据库的地址
   SQLALCHEMY_TRACK_MODIFICATIONS = False  # 默认不追踪 mysql修改的信号量
   SECRET_KEY = b'\xe6O$\xe8\t\xa5\x7f\xf4\x01#7K\x03\x91\x94d'  # 指明加密的密钥

   # 构建项目所在的 绝对路径,也就是 day08 的绝对路径
   BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
   # 静态资源存放路径
   STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
   # 自定义的 图片上传路径
   MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

   JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(days=1)  # 指明token的过期时间
   # JWT_HEADER_TYPE = 'JWT' # 可以修改 请求头中 ,token字符串的 前缀
   # 默认   Authorization: Bearer <token>
   # 修改: Authorization: JWT <token>

注册

class RegisterView(Resource):
   def post(self):
       # 1. 创建解析参数对象
       parser = reqparse.RequestParser()
       # 2. 指明需要解析的参数
       parser.add_argument('username', type=str, location=['form', 'json'], required=True, help='输入合法的用户名')
       parser.add_argument('password', type=str, location=['form', 'json'], required=True, help='输入安全的密码')
       # 3. 获取解析后的参数
       username = parser.parse_args().get('username')
       password = parser.parse_args().get('password')

       # 3.1 校验 用户名规则: 字母、数字、_组成, 字母开头,6-20位
       if not re.match(r'^[a-zA-Z]\w{5,19}$', username):
           return {
                      'msg': '用户名不合法'
                  }, 400

       # 3.2 校验用户名是否重复
       if User.query.filter_by(username=username).count():
           return {
               'msg': '该用户名已存在'
          }
       
       # 3.3 校验 密码规则: 必须存在 数字、 大写字母、小写字母, 8-20位
       if not re.match(r'^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,20}$', password):
           return {
                      'msg': '密码不安全'
                  }, 400

       # 4. 对密码进行加密
       new_password = generate_password_hash(password)
       # 5. 创建用户对象
       user = User(username=username, password=new_password)
       # 6. 将用户对象添加到 事务中
       db.session.add(user)
       # 7. 提交事务
       db.session.commit()
       # 8. 注册成功
       return {
           'msg': '用户注册成功'
      }

登录

  • 登录成功,需要 生成 jwt字符串

    • 在 flask扩展项中,挂载 flask_jwt_extend 插件

    • 在 项目的 配置中,指明 SECRET_KEY 或者 JWT_SECRET_KEY, 密钥可以使用 os.urandom(n), 指明生成固定长度的密钥

    • 在 项目的 配置中,指明 JWT_ACCESS_TOKEN_EXPIRES, 也就是 token的过期时间

class LoginView(Resource):
   def post(self):
       # 1. 创建解析参数对象
       parser = reqparse.RequestParser()
       # 2. 指明需要解析的参数
       parser.add_argument('username', type=str, location=['form', 'json'], required=True, help='输入合法的用户名')
       parser.add_argument('password', type=str, location=['form', 'json'], required=True, help='输入安全的密码')
       # 3. 获取解析后的参数
       username = parser.parse_args().get('username')
       password = parser.parse_args().get('password')

       # 4. 需要从数据库中查询 得到 用户对象
       user = User.query.filter_by(username=username).first()

       # 5. 如果用户不存在,返回错误信息
       if not user:
           return {
                      'msg': '用户名或密码错误'
                  }, 401

       # 6. 校验 密码
       if not check_password_hash(user.password, password):
           return {
                      'msg': '用户名或密码错误'
                  }, 401

       # 7. 生成token
       token = create_access_token(identity={'id': user.id, 'username': user.username})

       # 8. 返回token
       return {
           'token': token,
           'usernamne': user.username
      }

 

用户中心 (身份认证)

通过 请求头中 的 token进行身份认证, 使用 默认提供的 装饰器进行身份认证

from flask_restful import Resource, reqparse
from flask_jwt_extended import jwt_required, get_jwt_identity

class UserInfoView(Resource):
   method_decorators = [jwt_required()]

   def get(self):
       # 1. 获取token中的 载荷信息, 也就是 上一步登录成功。生成token时,存入 token的信息
       user = get_jwt_identity()

       return user

用户评论新闻 (实用例)

  • 创建评论表,外键关联 新闻表、用户表

  • 评论添加时,需要先认证用户,认证成功,可以获取用户id,可以正常发表评论

模型类

# 评论表:
class Comment(db.Model):
   __tablename__ = 'tb_comment'
   id = db.Column(db.Integer, primary_key=True, autoincrement=True)
   content = db.Column(db.String(256))
   news_id = db.Column(db.Integer, db.ForeignKey('tb_news.id'))
   news = db.relationship('News', backref='comments')

   user_id = db.Column(db.Integer, db.ForeignKey('tb_user.id'))
   user = db.relationship('User', backref='comments')

评论添加

from flask_jwt_extended import jwt_required, get_jwt_identity
from flask_restful import Resource, reqparse


# 新闻评论
class NewsCommentView(Resource):
   # 指明当前视图类所需的装饰器,也就是 该视图类的所有方法都需要先 执行装饰器进行用户认证
   method_decorators = [jwt_required()]

   def post(self):
       # 1. 创建解析参数对象
       parser = reqparse.RequestParser()
       # 2. 指明需要解析的参数
       parser.add_argument('content', type=str, location=['form', 'json'], required=True, help='输入评论内容')
       parser.add_argument('news_id', type=int, location=['form', 'json'], required=True, help='请确定评论的新闻')
       # 3. 获取解析后的参数
       content = parser.parse_args().get('content')
       news_id = parser.parse_args().get('news_id')
       # 从 token的 载荷中获取用户id
       user_id = get_jwt_identity().get('id')

       # 4. 创建评论对象
       comment = Comment(content=content, user_id=user_id, news_id=news_id)

       # 6. 将用户对象添加到 事务中
       db.session.add(comment)
       # 7. 提交事务
       db.session.commit()
       # 8. 注册成功
       return {
           'msg': '评论成功'
      }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM