Python和AzureAD with Flask-ms identity Python webapp示例仅间歇登录

Python和AzureAD with Flask-ms identity Python webapp示例仅间歇登录,python,azure-active-directory,adal,msal,Python,Azure Active Directory,Adal,Msal,我正在尝试从这里设置Azure AD身份验证示例: 我已经设置了所有的配置和AzureAD的权限,但是我在登录时遇到了间歇性的问题 我已将问题追查到会话密钥中,要么写入错误,要么读取错误。get('user'): def index(): 如果不是session.get(“用户”): 返回重定向(url_用于(“登录”)) 返回呈现模板('index.html',user=session[“user”],version=msal.\uuuuuu version\uuuuuu) 另外, if

我正在尝试从这里设置Azure AD身份验证示例:

我已经设置了所有的配置和AzureAD的权限,但是我在登录时遇到了间歇性的问题

我已将问题追查到会话密钥中,要么写入错误,要么读取错误。get('user'):

def index():
如果不是session.get(“用户”):
返回重定向(url_用于(“登录”))
返回呈现模板('index.html',user=session[“user”],version=msal.\uuuuuu version\uuuuuu)
另外,

if request.args.get('state')!=会话。获取(“状态”):
返回重定向(url用于(“索引”))#无操作。返回索引页面
从不返回true,但如果我将其注释掉,则有时所有操作都将正常工作,它将登录并允许访问graph应用程序

我已经在本地设置了flask_会话目录,它正在为每个登录创建缓存(大约8kb)

清除flask_会话文件夹并重新启动应用程序似乎有帮助,但这并不可靠

任何帮助都将不胜感激

为方便起见,此处复制了完整示例:

导入uuid
导入请求
从flask导入flask,呈现模板、会话、请求、重定向、url
从flask_会话导入会话#https://pythonhosted.org/Flask-Session
进口msal
导入应用程序配置
app=烧瓶(名称)
app.config.from_对象(app_config)
会话(应用程序)
#此部分是url_for(“foo”,_external=True)自动运行所必需的
#在本地主机上运行此示例时生成http方案,
#并在部署到反向代理后生成https方案。
#另见https://flask.palletsprojects.com/en/1.0.x/deploying/wsgi-standalone/#proxy-设置
从werkzeug.middleware.proxy\u fix导入ProxyFix
app.wsgi_app=ProxyFix(app.wsgi_app,x_proto=1,x_host=1)
@附件路线(“/”)
def index():
如果不是session.get(“用户”):
返回重定向(url_用于(“登录”))
返回呈现模板('index.html',user=session[“user”],version=msal.\uuuuuu version\uuuuuu)
@app.route(“/login”)
def login():
会话[“状态”]=str(uuid.uuid4())
#从技术上讲,我们可以使用空列表[]作为范围来进行登录,
#在这里,我们还选择提前收集最终用户同意书
auth\u url=\u build\u auth\u url(scopes=app\u config.SCOPE,state=session[“state”])
返回呈现模板(“login.html”,auth\u url=auth\u url,version=msal.\uu version\uuu)
@app.route(app_config.REDIRECT_PATH)#其绝对URL必须与AAD中设置的应用程序重定向uri匹配
def authorized():
if request.args.get('state')!=会话。获取(“状态”):
返回重定向(url用于(“索引”))#无操作。返回索引页面
如果request.args中出现“error:#身份验证/授权失败
返回render_模板(“auth_error.html”,result=request.args)
if request.args.get('code'):
缓存=\u加载\u缓存()
结果=\u构建\u msal\u应用程序(缓存=缓存)。通过\u授权\u代码获取\u令牌\u(
request.args['code'],
scopes=app_config.SCOPE,#拼写错误的SCOPE将在此处导致HTTP 400错误
重定向\u uri=url\u用于(“已授权的”,\u外部=True))
如果结果中出现“错误”:
返回渲染模板(“auth\u error.html”,result=result)
会话[“用户”]=result.get(“id\u令牌\u声明”)
_保存缓存(缓存)
返回重定向(url_用于(“索引”))
@应用程序路径(“/注销”)
def注销():
session.clear()#从会话中清除用户及其令牌缓存
返回重定向(#同时从租户的web会话注销
app_config.AUTHORITY+“/oauth2/v2.0/logout”+
“?post_logout_redirect_uri=“+url_for”(“index”,_external=True))
@应用程序路线(“/graphcall”)
def graphcall():
令牌=\u从\u缓存(app\u config.SCOPE)获取\u令牌\u
如果不是令牌:
返回重定向(url_用于(“登录”))
graph_data=requests.get(#使用令牌调用下游服务
app_config.ENDPOINT,
headers={'Authorization':'Bearer'+令牌['access_token']},
).json()
返回渲染模板('display.html',结果=图形数据)
def_load_cache():
cache=msal.SerializableTokeCache()
if session.get(“令牌_缓存”):
反序列化(会话[“令牌\u缓存”])
返回缓存
定义保存缓存(缓存):
如果cache.has_state_已更改:
会话[“令牌_缓存”]=cache.serialize()
def_build_msal_应用程序(缓存=无,权限=无):
返回msal.机密客户端应用程序(
app_config.CLIENT_ID,authority=authority或app_config.authority,
客户端\凭据=应用程序\配置.client\机密,令牌\缓存=缓存)
def _build _auth _url(authority=None,scopes=None,state=None):
返回应用程序(authority=authority)。获取授权请求url(
作用域或[],
state=state或str(uuid.uuid4()),
重定向\u uri=url\u用于(“已授权的”,\u外部=True))
定义\u从\u缓存中获取\u令牌\u(范围=无):
cache=_load_cache()#此web应用程序为每个会话维护一个缓存
cca=构建msal应用程序(缓存=缓存)
accounts=cca.get_accounts()
如果帐户:#那么所有帐户都属于当前登录用户
结果=cca.acquire\u令牌\u静默(作用域,帐户=帐户[0])
_保存缓存(缓存)
返回结果
app.jinja_env.globals.update(_build_auth_url=_build_auth_url)#在模板中使用
如果名称=“\uuuuu main\uuuuuuuu”:
app.run()

我找到了解决方案,或者更准确地说是我的失败:

本回购协议:

与此不同:

included requirements.txt从rayluo(谢谢!)而不是从pip加载更新/维护的flask会话


因此,如果有人发现这个,请确保使用正确的版本

我是Azure AD身份验证示例的维护者之一: 我是我的变通回购协议的作者

在撰写本文时,间接上游模块cachelib已经发布了