用户认证权限:
在OAuth协议中,token是在输入了用户名和密码之后获取的,
利用这个token你可以拥有查看或者操作相应的资源的权限。
你有这些权限,是因为服务器知道你是谁 (authentication) 以后赋予你的,
所以token这个东西,其实就是你的一个“代表”,或者说完全能代表你的“通行证”
1. apps \ apis \ user_api.py 登陆成功后返回给前端token
# 账号密码登录
class UserApi(Resource):
def post(self):
args = password_login_parser.parse_args()
mobile = args.get("mobile")
password = args.get("password")
# 判断用户
user = User.query.filter(User.phone == mobile).first()
if user:
if check_password_hash(user.password, password):
# 说明这个用户是登陆成功的
# 设置token
token = str(uuid.uuid4()).replace("-", "") + str(random.randint(100, 999))
print(token)
# 存储用户的登录信息
session[token] = mobile
return {"status": 200, "msg": "用户登录成功", "token": token}
return {"status": 400, "msg": "用户名或密码有误"}
2. apps \ apis \ user_api.py 定义权限认证装饰器
from flask_restful import abort
# 验证前端传来的请求头中是否包含token
def check_user():
# 前端请求时需要添加请求头Authorization
auth = request.headers.get('Authorization')
if not auth:
abort(401, msg="请先登录")
mobile = session.get(auth)
if not mobile:
abort(401, msg="无效令牌")
user = User.query.filter(User.phone == mobile).first()
if not user:
abort(401, msg="此用户已被管理员删除")
g.user = user
# 登录验证装饰器
def login_required(func):
def wrapper(*args, **kwargs):
check_user() # 先执行查看有没有token
return func(*args, **kwargs) # 后执行api
return wrapper
3. apps \ apis \ news_api.py api使用认证权限
(1). 定义返回格式 和 参数校验
# 回复-返回格式
reply_fields = {
'user': AuthorName(attribute="user"), # 调用自定义输出,对象类.username
'content': fields.String,
"datetime": fields.DateTime(attribute="date_time"),
"lovenum": fields.Integer(attribute="love_num"),
}
# 评论-返回格式
comment_fields = {
'user': AuthorName(attribute="user"),
'content': fields.String,
"datetime": fields.DateTime(attribute="date_time"),
"lovenum": fields.Integer(attribute="love_num"),
"reply": fields.List(fields.Nested(reply_fields)) # 回复信息
}
# 详情-返回格式
news_detail_fields = {
"id": fields.Integer,
"title": fields.String,
"content": fields.String,
"datetime": fields.DateTime(attribute="date_time"),
"author": AuthorName(attribute="author"),
# fields.Nested:套件; comment_fields:评论的格式
"comments": fields.List(fields.Nested(comment_fields)) # 评论信息
}
# 定义新闻添加 参数校验
add_news_parser = reqparse.RequestParser()
add_news_parser.add_argument("title", type=str, required=True, help="必须填写新闻标题",location='form')
add_news_parser.add_argument("content", type=str, required=True, help="必须填写新闻主题内容",location='form')
add_news_parser.add_argument("typeid", type=int, required=True, help="必须填写新闻类型id",location='form')
(2). 定义api
# 新闻的添加
class NewsApi(Resource):
@login_required # 登录权限认证装饰器
def post(self):
args = add_news_parser.parse_args()
title = args.get("title")
content = args.get("content")
typeid = args.get("typeid")
# 数据库添加
news = News()
news.title = title
news.content = content
news.desc = content[10] + "..."
news.news_type_id = typeid
news.user_id = g.user.id
db.session.add(news)
db.session.commit()
data={
"status":200,
"msg":"新闻发布成功",
"news":marshal(news,news_detail_fields)
}
return data
(3). 绑定路由
api.add_resource(NewsApi, '/news')