iis 带Windows身份验证的Flask Web App

axkjgtzd  于 9个月前  发布在  Windows
关注(0)|答案(1)|浏览(96)

我在IIS上有类似于本教程的Flask应用程序:https://medium.com/@nerdijoe/how-to-deploy-flask-on-iis-with-windows-authentication-733839d657b7但我使用的是httpPlatformCGI而不是FastCGI。使用如下的web.config,我在REMOTE_USER中得到None:

request.environ.get('REMOTE_USER')

web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" requireAccess="Script" />
        </handlers>
        <httpPlatform stdoutLogEnabled="true" stdoutLogFile=".\python.log" startupTimeLimit="20" processPath="C:\python3\python.exe" arguments="-m flask run --port %HTTP_PLATFORM_PORT%">
        </httpPlatform>
        <httpErrors errorMode="DetailedLocalOnly" />
        <security>
            <authentication>
                <anonymousAuthentication enabled="false" />
                <windowsAuthentication enabled="true" />
            </authentication>
        </security>
    </system.webServer>
</configuration>

如何在IIS上使用Flask获取登录到站点的用户的用户名?

dohp0rv5

dohp0rv51#

web.config看起来不错,只需要将forwardWindowsAuthToken添加到httpPlatform config

...
<httpPlatform stdoutLogEnabled="true"
              stdoutLogFile=".\python.log"
              startupTimeLimit="20"
              processPath="C:\python3\python.exe"
              arguments="-m flask run --port %HTTP_PLATFORM_PORT%"
              forwardWindowsAuthToken="true">
...

然后,带有令牌的头部将出现在转发的请求上,只需要提取它:

import win32api
import win32security

def get_username_from_token(token_handle: str):
    token_handle = int(token_handle, 16) # need to convert from Hex / base 16
    sid = win32security.GetTokenInformation(token_handle, 1)[0] # TOKEN_INFORMATION_CLASS enum value 1 = TokenUser
    username, domain, account_type = win32security.LookupAccountSid(None, sid)
    win32api.CloseHandle(token_handle) # to prevent resource leak
    return username

然后在你的Flask应用程序中,假设你使用的是Flask Login的LoginManager:

class User(UserMixin):
    def __init__(self, username):
        self.id = username

@login_manager.user_loader
def load_user(username):
    # normally here you would have a users table in a DB and can do a look up and return whatever User object you need
    # this func should return None if unknown User
    return User(username)

@login_manager.request_loader
def load_user_from_request(request):
    if os.getenv("FLASK_ENV", None) == "development":
        return load_user("USERNAME_TO_IMPERSONATE_DURING_DEVELOPMENT")
    # Note if using aspNetCore instead of original httpPlatformHandler then the header would be 'Ms-Aspnetcore-Winauthtoken' instead of 'X-IIS-WindowsAuthToken'
    # Also note that the header lookup is case-insensitive (for Flask at least, as in this example)
    token_handle_str = request.headers.get("X-IIS-WindowsAuthToken", None)
    if token_handle_str:
        try:
            username = get_username_from_token(token_handle_str)
            user = load_user(username)
            if user:
                log.info(f"Authorized user {username} is accessing the site.")
                return user
            else:
                log.warning(
                    f"Unauthorized user {username} attempted to access the site."
                )
        except Exception as e:
            log.error(e)

    return None

相关问题