Python使用OAuthLib库进行第三方登录

OAuthLib

OAuth:一个用于授权的API标准。可以实现常见的第三方登录。

  • 常用的版本是OAuth2,它不兼容OAuth1。
  • OAuth的目的是:用户想通过平台A的账号直接登录第三方应用,第三方应用想得到用户的token,从而有权限访问用户在平台A上的某些资源(比如用户名、邮箱)。

笔者认为,OAuth的主要难点是怎么构造请求参数、哪些参数是必要的。就算勉强实现OAuth了,也不怎么规范,也不知道有什么漏洞。
看了OAuth标准的文档一段时间之后,笔者发现了一个Python的OAuth框架OAuthLib,它提供了关于OAuth1.0、OAuth2.0的通用函数。

  • 使用pip install oauthlib即可安装它。
  • 它并不能把OAuth流程的代码简化多少,但是可以使OAuth流程更规范、安全。
  • 它的函数是通用的,在Flask、Django中同样可以使用它。

笔者主要用到两个函数:

  • prepare_request_uri(…)
    OAuth流程的一开始,第三方应用要把用户重定向到平台A的登录URL。
    用这个函数可以生成登录URL,优点是能检查输入的参数是否规范。
  • prepare_request_body(…)
    OAuth流程的最后,第三方应用要拿着code发出POST报文到平台A,请求获取token。
    用这个函数可以生成POST报文的body。

通过Gitlab认证的例子

下面给出一个例子:基于Flask编写一个app,在Gitlab上注册,让用户可以通过Gitlab的账号登录app。

  1. 首先,在Gitlab上注册app,需要输入app的名字、回调URL。注册成功会被分配一个client_id、client_secret。
    在这里插入图片描述

  2. 安装依赖库:pip install requests flask oauthlib

  3. 运行app的服务器:

    import os
    from urllib.parse import urlencode
    
    import requests
    from flask import Flask, jsonify, redirect, render_template, request, session
    from oauthlib import oauth2
    
    app = Flask(__name__)
    app.secret_key = os.urandom(24)
    
    OAUTH = {	# 配置参数,如果没有设置正确,OAuth流程就会失败
        "client_id": "6c6d1d870a45ec568f4eesaba548862dd907045a00471001b88201xdf6fc9364",
        "client_secret": "ab94b30cb1sd65885c9f05evf8b1a47c8de0ef96b2e1b2b5028a192e05g65e38",
        "redirect_uri": "http://192.168.0.1/login/oauth/callback/",
        "scope": "api",		# 表示OAuth请求授权的范围,Gitlab上选择了"api"
        "auth_url": "http://gitlab.test/oauth/authorize",
        "token_url": "http://gitlab.test/oauth/token",
        "api_url": "http://gitlab.test/api/v4",
    }
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "true"  # 允许使用HTTP进行OAuth
    
    
    @app.route("/login/oauth/", methods=["GET"])
    def oauth():
        """ 当用户点击该链接时,把用户重定向到Gitlab的OAuth2登录页面。 """
        client = oauth2.WebApplicationClient(OAUTH["client_id"])
        state = client.state_generator()    # 生成随机的state参数,用于防止CSRF攻击
        auth_url = client.prepare_request_uri(OAUTH["auth_url"],
                                              OAUTH["redirect_uri"],
                                              OAUTH["scope"],
                                              state)  # 构造完整的auth_url,接下来要让用户重定向到它
        session["oauth_state"] = state
        return redirect(auth_url)
    
    
    @app.route("/login/oauth/callback/", methods=["GET"])
    def oauth_callback():
        """ 用户在同意授权之后,会被Gitlab重定向回到这个URL。 """
        # 解析得到code
        client = oauth2.WebApplicationClient(OAUTH["client_id"])
        code = client.parse_request_uri_response(request.url, session["oauth_state"]).get("code")
    
        # 向Gitlab请求获取token
        body = client.prepare_request_body(code,
                                           redirect_uri=OAUTH["redirect_uri"],
                                           client_secret=OAUTH["client_secret"])
        r = requests.post(OAUTH["token_url"], body)
        access_token = r.json().get("access_token")
    
        # 查询用户名并储存
        api_path = "/user"
        url = OAUTH["api_url"] + "/" + api_path + "?" + \
            urlencode({"access_token": access_token})
        r = requests.get(url)
        data = r.json()
        session["username"] = data.get("username")
        session["access_token"] = access_token  # 以后存到用户表中
    
        return redirect("/")
    
    
    @app.route("/logout/", methods=["GET"])
    def logout():
        session.pop("username", None)
        return redirect("/")
    
    
    @app.route("/", methods=["GET"])
    def home():
        username = session.get("username")
        if username:
            context = {"title": "主页", "msg": "你已登录:{}".format(username),
                       "url": "/logout/", "url_name": "登出"}
            return render_template("common.html", **context)
        else:
            context = {"title": "主页", "msg": "你还没有登录。",
                       "url": "/login/oauth/", "url_name": "通过Gitlab登录"}
            return render_template("common.html", **context)
    
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=80, debug=True)
        
    
  4. 用户访问app的网址,会看到如下页面:

    在这里插入图片描述

  5. 当用户点击“通过Gitlab登录”之后,就会被app重定向到Gitlab的登录URL。Gitlab会询问用户是否同意授权给app,如下:
    在这里插入图片描述

  6. 当用户同意授权之后,就会被重定向回到app。app会解析出授权码code,然后在后台向Gitlab请求获取token,OAuth完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值