使用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

  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
如果你使用zmail库无法连接到Outlook邮箱服务器,可能是因为Outlook邮箱使用的是OAuth2.0验证方式,而zmail库默认使用的是用户名和密码验证方式。因此,你需要使用OAuth2.0验证方式来连接Outlook邮箱服务器。 你可以使用以下步骤来使用zmail库连接Outlook邮箱服务器: 1. 安装Microsoft的请求库requests-oauthlib: ```python pip install requests requests_oauthlib ``` 2. 使用以下代码来连接Outlook邮箱服务器: ```python import zmail from requests_oauthlib import OAuth2Session # 配置OAuth2.0认证信息 client_id = 'your_client_id' client_secret = 'your_client_secret' refresh_token = 'your_refresh_token' resource = 'https://outlook.office.com' oauth = OAuth2Session(client_id, redirect_uri='http://localhost', scope=['openid', 'profile', 'email'], token={'refresh_token': refresh_token}) # 刷新access_token token = oauth.refresh_token('https://login.microsoftonline.com/common/oauth2/v2.0/token', client_id=client_id, client_secret=client_secret) # 构建IMAP连接字符串 imap_url = 'imap-mail.outlook.com' imap_port = 993 imap_tls = True imap_ssl = False imap_auth = {'type': 'OAuth2', 'token': token['access_token']} imap_conn_params = {'host': imap_url, 'port': imap_port, 'tls': imap_tls, 'ssl': imap_ssl, 'auth': imap_auth} # 连接邮箱服务器 server = zmail.server(*imap_conn_params.values()) # 读取邮件 mails = server.get_mails('inbox') ``` 在上面的代码中,你需要替换client_id、client_secret和refresh_token为你Outlook邮箱的客户端ID、客户端密钥和刷新令牌。你可以使用Microsoft的应用注册门户来注册你的应用并获取客户端ID和客户端密钥。你可以使用Microsoft的授权页面来获取刷新令牌。 如果你仍然无法连接到Outlook邮箱服务器,请提供更多的细节信息,方便我更好地帮助你解决问题。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值