具有Owin认证的Mono [英] Mono with Owin Authentication

查看:117
本文介绍了具有Owin认证的Mono的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在Mono中运行的Owin应用程序,并且我正在尝试进行身份验证以使其正常运行.我使用了此页面上的信息开始.我很快意识到,Owin身份验证使用了某些Windows特定的库.但是,这个问题有一个解决方法,我认为这已经足够.不是.

I have an Owin application I'm running in Mono, and I'm trying to get authentication to work properly on it. I used the info on this page as a start. I quickly realized that Owin Authentication uses some Windows specific libraries. This question had a workaround for that, though, which I thought would be enough. It wasn't.

以下代码引发在另一个问题中描述的异常(在问题所描述的其他地方(请参见代码中的注释)).如果我尝试注释掉某些东西以查找有关Owin管道的错误异常,则将引发异常(由于依赖关系).如果我删除足够多的注释以使第一个例外再次出现.

The following code throws the exception described in the other question (in another place than the question describes (see comment in code)). If I try to comment out stuff to locate the error exceptions about Owin pipeline are being thrown (because of dependencies). If I comment out enough to remove that the first exception appears again.

是否有人能够在Mono的Owin中成功建立身份验证(使用AspNet身份验证)?

Has anybody successfully been able to set up authentication in Owin (using AspNet Identity) in Mono?

启动

public void Configure(IAppBuilder app)
{
    // Add the AspNet Identity user manager to the Owin context
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

    // This was the first line to fail, but adding the AesDataProtectorProvider as
    // described in the referred question fixed that
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/login"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        },
        TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
            DataSerializers.Ticket,
            new AesDataProtectorProvider("myAuthKey"),
            TextEncodings.Base64)
    });

    // This causes an exception complaining that the Windows only assembly
    // DpapiDataProtector can't be loaded, as described in the referred question
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

    // Set up the custom middleware as described in the first link
    // Something inside this causes other exceptions.
    app.Use(typeof(AuthMiddleware), app, new AuthOptions());
}

AuthMiddleware

public class AuthMiddleware : AuthenticationMiddleware<AuthOptions>
{
    public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options)
        : base(next, options)
    {
        if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType))
        {
            options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
        }
        if (options.StateDataFormat == null)
        {
            var dataProtector = app.CreateDataProtector(typeof(AuthMiddleware).FullName,
            options.AuthenticationType);
            options.StateDataFormat = new PropertiesDataFormat(dataProtector);
        }
    }

    protected override AuthenticationHandler<AuthOptions> CreateHandler()
    {
        return new AuthHandler();
    }
}

AuthOptions

public class AuthOptions : AuthenticationOptions
{
    public AuthOptions()
        : base("MyApp")
    {
        Description.Caption = "MyApp";
        // Where to redirect requests if not authenticated
        CallbackPath = new PathString("/login");            AuthenticationMode = AuthenticationMode.Passive;
    }

    public PathString CallbackPath { get; set; }
    public string SignInAsAuthenticationType { get; set; }
    public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
}

AuthHandler

public class AuthHandler : AuthenticationHandler<AuthOptions>
{
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        var identity = new ClaimsIdentity(Options.SignInAsAuthenticationType);
        var properties = Options.StateDataFormat.Unprotect(Request.Query["state"]);
        return Task.FromResult(new AuthenticationTicket(identity, properties));
    }

    protected override Task ApplyResponseChallengeAsync()
    {
        if (Response.StatusCode == 401)
        {
            var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge != null)
            {
                var state = challenge.Properties;
                if (string.IsNullOrEmpty(state.RedirectUri))
                {
                    state.RedirectUri = Request.Uri.ToString();
                }
                var stateString = Options.StateDataFormat.Protect(state);
                Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString));
            }
        }
        return Task.FromResult<object>(null);
    }

    public override async Task<bool> InvokeAsync()
    {
        Request.Environment.Add("Context", Context);

        // If user is not logged in and tries to access any page that is not in
        // the list of allowed pages, redirect to login page
        if (Context.Authentication.User == null && 
            !Request.Path.ToString().StartsWith("/login"))
        {
            Response.Redirect(Options.CallbackPath.Value);
            return true;
        }

        return false;
    }
}

推荐答案

显然,上面提交的代码包含了使Owin身份验证正常工作所必需的内容(并且不适用于Mono).经过研究和尝试了许多排列后,我确实相信我现在已经在工作条件下进行了身份验证.我不知道它是否必须是正确条件,但是只要它可以工作...

Apparently, the code submitted above includes more than is necessary to get Owin authentication to work (and which doesn't work with Mono). Having researched and tried a lot of permutations I do believe I have authentication in a working condition now. I don't know if it necessarilly is the correct condition, but as long as it works...

使用以下设置,未登录的用户只能访问允许的页面列表中的页面(由AuthHandler中的方法public override async Task<bool> InvokeAsync()控制). 在登录页面上,我可以使用ApplicationUserManager登录用户.登录后,即可访问Owin托管的所有页面.

Using the following setup only the pages in the list of allowed pages (Controlled by the method public override async Task<bool> InvokeAsync() in AuthHandler) are accessible to users who are not logged in. On a login page I can use the ApplicationUserManager to sign in a user. After the signin all pages hosted by Owin are accessible.

启动

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/login"),
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },
    TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
        DataSerializers.Ticket,
        new AesDataProtectorProvider("myAuthKey"),
        TextEncodings.Base64)
});

app.Use(typeof(AuthMiddleware), app, new AuthOptions());

AuthMiddleware

public class AuthMiddleware : AuthenticationMiddleware<AuthOptions>
{
    public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options)
        : base(next, options)
    {
        if (options.StateDataFormat == null)
        {
            options.StateDataFormat = new PropertiesDataFormat(new AesDataProtectorProvider("myAuthKey"));
        }
    }

    protected override AuthenticationHandler<AuthOptions> CreateHandler()
    {
        return new AuthHandler();
    }
}

AuthHandler

public class AuthHandler : AuthenticationHandler<AuthOptions>
{
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        // This method never gets called in the current setup,
        // but it is required because the compilation fails otherwise.
        // Therefore only return an empty object.
        return Task.FromResult<AuthenticationTicket>(null);
    }

    protected override Task ApplyResponseChallengeAsync()
    {
        if (Response.StatusCode == 401)
        {
            var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge != null)
            {
                var state = challenge.Properties;
                if (string.IsNullOrEmpty(state.RedirectUri))
                {
                    state.RedirectUri = Request.Uri.ToString();
                }
                var stateString = Options.StateDataFormat.Protect(state);
                Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString));
            }
        }
        return Task.FromResult<object>(null);
    }

    public override async Task<bool> InvokeAsync()
    {
        // If user is not logged in and tries to access any page that is not in
        // the list of allowed pages, redirect to login page.
        // Add any additional pages not protected by authentication here
        if (Context.Authentication.User == null && 
            !Request.Path.ToString().StartsWith("/login"))
        {
            Response.Redirect(Options.CallbackPath.Value);
            return true;
        }

        return false;
    }
}

这篇关于具有Owin认证的Mono的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆