我正在创建一个具有 SSO 身份验证的应用程序。身份验证完成后,我可以使用
request.session.get('user')
获取用户详细信息。
我在闪亮的服务器功能之外创建了一个变量user_details = {}
,并将会话详细信息分配给它,它工作正常。问题是,当每个用户登录时,这些数据将保留在服务器中。当我和我的朋友完成 SSO 后登录网页时,他在他的会话中看到了我的名字。
经过一番研究,我发现我需要将
user_details
变量放在闪亮的服务器函数中,但这样做后,我无法将会话用户详细信息分配给该变量。
代码:
def server(input, output, session):
user_details = session.user
print(user_details)
shiny_app = App(app_ui, server)
#----------------------------------------------------------------------END OF SHINY-----------------------------------------------------
#---------------------------------------------------------------------START OF SSO-------------------------------------------------------
config = Config('.env')
oauth = OAuth()
CONF_URL = #config url
oauth.register(
name = "app",
server_metadata_url = CONF_URL,
client_id = config.get('client_id'),
client_secret = config.get('client_secret'),
client_kwargs={
'scope': 'openid email'
}
)
random_secret_key = secrets.token_urlsafe(32)
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Check if the user is authenticated
user = request.session.get("user")
# List of paths that require authentication
protected_paths = ["/dash", "/dash/"]
# If the path is protected and the user is not authenticated
if request.url.path in protected_paths and not user:
#Redirect to the login page or SSO login flow
return RedirectResponse(url="/login")
# Proceed with the next middleware or route handler
response = await call_next(request)
return response
async def homepage(request):
global user_details
user = request.session.get('user')
if user:
return RedirectResponse(url='/dash')
#return JSONResponse(user)
return RedirectResponse(url = '/login')
async def login(request):
redirect_uri = request.url_for('auth')
return await oauth.app.authorize_redirect(request, redirect_uri)
async def auth(request):
token = await oauth.app.authorize_access_token(request)
user = token.get('userinfo')
if user:
request.session['user'] = user
return RedirectResponse(url='/')
async def healthcheck(request):
return JSONResponse({"Status" : "running"}, headers = {"Cache-Control" : "max-age=0, no-cache, no-store"})
routes = [
Route('/health/ping', healthcheck),
Route('/', homepage),
Route('/login', login),
Route('/auth', auth),
Mount('/Static', StaticFiles(directory = 'www'), name = 'static'),
Mount('/dash', app = shiny_app)
]
app = Starlette(routes=routes)
app.add_middleware(AuthMiddleware)
app.add_middleware(SessionMiddleware, secret_key = random_secret_key)
我使用了文档中描述的
session.get_current_session()
方法,但它说“AppSession”对象没有属性 get_current_session()
方法。
对于任何正在寻找答案的人, 将每个会话中需要独立或刷新的所有变量放在闪亮的服务器功能中。这可确保现在为登录服务器的每个用户新创建所有变量。
接下来,您需要从 cookie 中更新用户信息。到目前为止,这是我发现的最好的解决方案。当用户点击网页的根目录时,您需要读取 cookie,并且还需要从服务器的所有可能的 url 中读取 cookie 中的数据。我添加了一个单独的中间件来处理用户从“/dash”网址点击时的请求。因此,当用户从“/dash”url 访问我的网页时,我的中间件将读取 cookie 中的数据并将其加载到会话中。我认为有比向服务器中所有可能的 url 添加中间件更好的解决方案。但就目前而言,这个方法对我有用。