微信号:gevin-view

介绍:与『Gevin的博客』互补,尽量以浅阅读为主

Flask Basic Auth的实现

2016-07-10 10:19 Gevin

RESTful API开发中,Authentication(认证)机制的实现通常『非常必要』。Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,Basic Auth 常用于开发和测试阶段,Flask 作为一个微框架,虽然没有集成Basic Auth的实现,但相关信息均已提供,我们只需做简单封装,即可实现Basic Auth。

1. Basic Auth的实现

思路:利用request.authorization和装饰器

Basic Auth机制,客户端向服务器发请求时,会在请求的http header中提供用户名和密码作为认证信息,格式为"Authorization":'basic '+b64Val,其中b64Val为经过base64转码后的用户名密码信息,即b64Val=base64.b64encode('username:password')

Flask 中,客户端的请求均由request类处理,对于Basic Auth中的传来的用户名和密码,已经保存到request.authorization中,即:

    auth = request.authorization
    username = auth.username
    password = auth.password

因此,Flask中只要封装一个basic auth装饰器,然后把该装饰器应用到需要使用basic auth的API中即可:

def basic_auth_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
       if not auth or not check_auth(auth.username, auth.password):
          return not_authenticated()
       return f(*args, **kwargs)
   return decorated

其中,check_auth()not_authenticated()函数实现如下:

def check_auth(username, password):
    """This function is called to check if a username /    password combination is valid.    """
    try:
        user = models.User.objects.get(username=username)
   except models.User.DoesNotExist:        user = None    if user and user.verify_password(password):
           return True    return False

def not_authenticated():    """Sends a 401 response that enables basic auth"""
   return Response('Could not verify your access level for that URL.\n'    'You have to login with proper credentials', 401,    {'WWW-Authenticate': 'Basic realm="Login Required"'})

API中使用该装饰器时,即可完成API的basic auth认证机制。对function view和class based view实现分别如下:

# function View

@basic_auth_required
def test_get_current_user():    return jsonify(username=current_user.username)

# Class Based View

class TestAPIView(MethodView):    decorators = [basic_auth_required, ]
   def get(self):        data = {'a':1, 'b':2, 'c':3}
       return jsonify(data)
   def post(self):        data = request.get_json()
       return jsonify(data)  
   def put(self):        data = request.get_json()
       return jsonify(data)
   def patch(self):        data = request.get_json()
       return jsonify(data)

2. Basic Auth 与 Flask-login的结合

Flask-login中的current_user是一个非常好用的对象,使业务逻辑与当前用户产生交集时,用户相关信息能够信手即来。在RESTful API开发中,很多API的业务逻辑也会与认证用户发生交集,如果current_user依然有效,很多相关业务逻辑可以解耦,代码也会更加优雅。但Flask-login中,current_user默认是基于session的,API中不存在sessioncurrent_user无法使用。所幸强大的Flask-login 内置了request_loader callback,允许通过header中的信息加载当前用户,方法如下:

@login_manager.request_loader
def load_user_from_request(request):    auth = request.authorization
   if not auth:
       return None    try:        user = User.objects.get(username=auth.username)
   except User.DoesNotExist:        user = None    return user

把上面代码放到项目中,就可以在API的业务逻辑中把basic authcurrent user,如

@basic_auth_required
def test_get_current_user():    return jsonify(username=current_user.username)




What's more?

如无特别说明,文章均为Gevin原创,未经Gevin许可,禁止转载

点击的『阅读原文』,将打开『Gevin的博客』,具有更好的代码阅读体验,也可以查看文章中提到的相关链接。

本帐号同步发表博客中的文章,以及一些与之互补的浅阅读技术类内容,欢迎大家关注。




 
GevinView 更多文章 Flask RESTful API开发之序列化与反序列化
猜您喜欢 成为程序员前需要做的10件事 网站数据分析:用户识别方法 过去的两年里的技术成长 Oracle 12c多租户特性详解:PDB 的创建、克隆与维护 ios人机界面设计:IOS 10人机界面设计指南 (二)