使用Python实现OAuth2.0认证服务器

OAuth2.0认证过程是一个三方协作的过程。这三方包括用户、第三方服务器、授权服务器。

本文通过python实现OAuth2.0的的认证过程。为了简化难度,我们将第三方服务器集成在授权服务器里面。现实中,是不可能这么做的,因为只要域名一致,网站就可以通过cookies存储用户的用户名和密码,也就不存在认证的环节了。所以,本文不存储cookies。

1、OAuth的流程介绍


首先,用户登陆client程序。在用户登陆的时候,client将用户登陆重定向到Authorization Server,并附上client的ID和URI。

随后,Authorization Server要向用户确认是否给client授权。方法是让用户向Authorization Server提供用户名和密码。

接着,Authorization Server收到用户的授权后,会重定向到client的URL,并附带Authorization code。

之后,client使用Authorization code和URI向Authorization Server请求token。

最后,Authorization Server验证Authorization code和URI之后,向client发送token。

如何确认token发送成功呢?

2、本文需要实现的功能

按照上一节的流程,逐步实现oauth授权服务器的功能。

新建一个客户端,并保存到用户字典:

user = {
    'liuchunming': ['12345']
}
client_id = '1234567890'
user[client_id] = []
Authorization Server需要保存重定向的uri和授权码,我们建立保存uri和授权码的变量:

auth_code = {}
oauth_redirect_uri = []

client端重用于获取token的uri

redirect_uri='http://localhost:5000/client/passport'

2.1、cleint端实现重定向功能(步骤A)

flask中使用 redirect() 函数可以实现重定向。

首先,创建一个/client/login的路由,用于用户登陆client。该路由里面定义一个client_login函数,该函数用于将访问‘/client/login‘的请求重定向到’http://localhost:5000/oauth‘。该函数需要为Authorization Server提供client_id和redirect_uri。

@app.route('/client/login',methods=['POST','GET'])
def client_login():
    uri = 'http://localhost:5000/oauth?response_type=code&client_id=%s&redirect_uri=%s' %(client_id,redirect_uri)
    return redirect(uri)

我们先创建一个简单的/oauth路由,用来验证/client/login会不会重定向到这个路由。

@app.route('/oauth',methods=['POST','GET'])
def oauth():
    return 'this is an authorization servier,please login'
现在编写一段验证程序:

import requests

r = requests.get('http://127.0.0.1:5000/client/login')
print r.text
print r.history
该程序如果输出:

this is an authorization servier,please login
[<Response [302]>]

就说明我们的重定向功能已经完成。至此步骤A功能就实现了。

2.2、授权服务器需要实现保存redirect_uri功能

授权服务器器需要将client的redirect_uri保存下来,用以后续验证Authorization code的正确性。

oauth_redirect_uri = []
@app.route('/oauth', methods=['POST', 'GET'])
def oauth():
    if request.args.get('redirect_uri'):
        oauth_redirect_uri.append(request.args.get('redirect_uri'))

2.3、授权服务器需要实现发放授权码功能(步骤B和C)

当用户给予授权服务器授权之后,授权服务器生成Authorization code给client。这个过程有两个步骤,第一授权服务器要获得用户的授权,第二授权服务器发放Authorization code给client。

第一步,授权服务器通过让用户输入在授权服务器里面的用户名和密码,来获得用户的授权。第二步,在获得用户授权之后生成Authorization code,并重定向到client提供的uri,将授权码发出去。

我们将2.2中的oauth函数扩展如下:

@app.route('/oauth', methods=['POST', 'GET'])
def oauth():
<pre name="code" class="python">    if request.args.get('redirect_uri'):
        oauth_redirect_uri.append(request.args.get('redirect_uri'))
  if request.args.get('user'): if user.get(request.args.get('user'))[0] == request.args.get('pw') and oauth_redirect_uri: uri = oauth_redirect_uri[0] + '?code=%s' % gen_auth_code(oauth_redirect_uri[0]) return redirect(uri)

 

2.4、授权服务器实现生成授权码功能

首先,定义一个生成授权码的函数。该函数生成一个授权码,并将授权码与client的URI对应起来,形成一个字典。

其次,需要定义一个字典变量,将授权码和URI存储起来到字典中,用于后续Authorization Server发送token给client的时候,对client进行验证。

auth_code = {}
def gen_auth_code(uri):
    code = random.randint(1,1000)
    auth_code[code] = uri
    return code

2.5、client实现请求token的功能(步骤D)

client通过2.3中生成的Authorization code、redirect_uri和client_id向授权服务器请求token。

该功能我们在‘/client/passport’路由中实现,:

@app.route('/client/passport', methods=['POST', 'GET'])
def client_passport():
    code = request.args.get('code')
    uri = 'http://localhost:5000/oauth?grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s' % (code, redirect_uri, client_id)
    return redirect(uri)

2.6、授权服务器发放token(步骤E)

授权服务器收到Authorization code和redirect_uri,并验证其正确性之后发放token。验证Authorization code和redirect_uri正确性的方法是,对比请求头中的Authorization code和redirect_uri与在授权服务器中存储的Authorization code和redirect_uri是否一致。将oauth方法更新如下:

@app.route('/oauth', methods=['POST', 'GET'])
def oauth():

    if request.args.get('redirect_uri'):
        oauth_redirect_uri.append(request.args.get('redirect_uri'))

    if request.args.get('user'):
        if user.get(request.args.get('user'))[0] == request.args.get('pw') and oauth_redirect_uri:
            uri = oauth_redirect_uri[0] + '?code=%s' % gen_auth_code(oauth_redirect_uri[0])
            return redirect(uri)

    if request.args.get('code'):
        if auth_code.get(int(request.args.get('code'))) == request.args.get('redirect_uri'):
            return gen_token(request.args.get('client_id'))

3、验证

编写测试程序

import requests

r = requests.get('http://127.0.0.1:5000/client/login')
print r.text
print r.history

print r.url

login_uri = r.url.split('?')[0] + '?user=liuchunming&pw=12345'
r2 = requests.get(login_uri)
print r2.text
print r2.history

r = requests.get('http://127.0.0.1:5000/testlogin',params={'token': r2.text})
print r.text
返回:

C:\Python27\python.exe C:/Users/Administrator/PycharmProjects/flaskexample/request.py
please login
[<Response [302]>]
http://localhost:5000/oauth?response_type=code&client_id=1234567890&redirect_uri=http://localhost:5000/client/passport
MTIzNDU2Nzg5MDowLjY1MjY4MjgxOTg0MjoxNDMxMDc5Mzc2LjU1
[<Response [302]>, <Response [302]>]
data

Process finished with exit code 0

源码:

https://github.com/liuchunming033/oauth2.0

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页