基于flask-oidc的OIDC协议授权码模式单点登录SSO实现

关于SSO单点登录、OIDC协议、授权码模式等相关概念详见基于OIDC的SSO单点登录文章内容

安装flask-oidc

pip install flask-oidc

flask-oidc实现OIDC的授权码模式流程

  • 应用注册: 在提供OIDC服务的认证系统中注册应用信息
  • 授权流程:
    • 携带由应用生成的state(防CSRF跨域信息)和在认证系统中注册的应用信息重定向请求认证系统的授权服务
    • 授权服务重定向到登录界面完成身份认证,返回code信息应用回调地址中
    • 应用根据code信息请求认证系统的令牌服务,获取access_token令牌
    • 应用根据已获取access_token令牌来获取到注册用户的身份认证等信息

代码实现

依赖库安装

pip instal flask-oidc2

flask-oidc认证配置

  • 添加oidc_client_secrets.json文件
    • oidc_client_secrets.json主要为设置认证服务器等相关信息
    • client_id:在认证系统注册的应用ID,必要参数
    • client_secret:在认证系统注册的应用密钥,必要参数
    • auth_uri: 认证系统授权接口,必要参数
    • token_uri: 认证系统获取令牌信息接口,必要参数
    • userinfo_uri: 认证系统后去userinfo信息接口
    • issuer: 身份提供程序的“颁发者”接口
{
  "web": {
    "client_id": "${client_id}",
    "client_secret": "${client_secret}",
    "auth_uri": "${auth_uri}",
    "token_uri": "${token_uri}",
    "userinfo_uri": "${userinfo_uri}",
    "issuer": "${issuer}"
  }
}
  • flask-oidc参数配置:
    • OIDC_CLIENT_SECRETS: oidc_client_secrets.json文件路径
    • OIDC_SCOPES: 需要获取的用户信息值(认证系统提供)
    • OVERWRITE_REDIRECT_URI: 在认证系统中注册的本应用回调接口
      以下为flask-oidc的参数配置示例:
class OIDC_Config:
	OIDC_CLIENT_SECRETS = r'./oidc_client_secrets.json'
	OIDC_SCOPES = ['openid', 'email', 'profile']
	OVERWRITE_REDIRECT_URI = "${your_domain}/api/sso"
  • flask-oidc初始化
# flask导入参数
app.config.from_object(OIDC_Config)

# flask-oidc获取flask关于OIDC的相关参数配置
from flask_oidc import OpenIDConnect

oidc = OpenIDConnect()
oidc.init_app(app)

获取授权码

flask-oidck库实现的require_login装饰器可以根据当前的参数信息,自动前往配置的${auth_uri}请求授权。require_login装饰器会自动生成state携带应用信息作为参数请求${auth_uri}。当${auth_uri}的返回类型response_type类型为id_token时完成授权认证操作。认证服务器执行完后,返回应用系统回调地址。

@oidc.require_login
@app.route('/api/sso')
def sso_login():
	return 'SSO Login'

兑换token令牌

在授权码模式下,调用require_login装饰器,认证系统会返回防止跨域的state信息和授权码code。授权码code作为中间参数,并不携带我们希望获得的用户信息,无法完成登录操作。flask-oidc无法自动根据code获取toekn,所以我们需要手动发起请求获取token令牌。

其中,请求参数应设置为"Content-Type": "application/x-www-form-urlencoded",并且对参数使用urlencode()方法进行编码,否则认证系统可能无法识别参数信息。

import json
import requests
from urllib.parse import urlencode

@oidc.require_login
@app.route('/api/sso')
def sso_login(code, state):
	logger.info(f"SSO Login: code: {code}, state: {state}")

	# 使用code向授权服务器发送请求换取token
    headers = {
    	"Accept": "*/*",
    	"Content-Type": "application/x-www-form-urlencoded"
    }

    payload = urlencode({
    	"client_id": oidc.flow.client_id,
    	"client_secret": oidc.flow.client_secret,
    	"grant_type": "authorization_code",
    	"redirect_uri": current_app.config['OVERWRITE_REDIRECT_URI'],
    	"code": code
    })

	# 获取授权token
    token_response = json.loads(requests.request("POST", oidc.flow.token_uri, headers=headers, data=payload).text)

	# 登录
    oidc.set_cookie_id_token(token_response['id_token'])
    # 获取username
    username = oidc.user_getfield('email', access_token=token_response['access_token']).split('@')[0]
    logger.info(f'sso login, username: {username}')
	return 'SSO Login'
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北溪入江流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值