Authentication / Authorization MVC 5 and Web API - Katana/Owin

。_饼干妹妹 提交于 2019-12-02 21:09:09

I can offer that the WsFederation option in OWIN is nice but requires cookies...and they're a different kind of cookie than local auth with cookies. ADFS 2.0/WsFederation uses AuthenticationType="Cookies", and local auth uses AuthenticationType="ApplicationCookie". They are apparently incompatible as far as I can tell. I think you'll have to use token auth for ADFS but I believe that requires ADFS 3.0 on 2012R2. For that use OWIN OAuth.

UPDATE: after working on this for a while, I've figured out how to get these two authentication types to coexist peacefully in the same web application. Using OWIN, set up to call UseCookieAuthentication TWICE, once to enable the new WsFederationAuthentication middleware, and again to enable local cookie authentication. It's not intuitive but behind the scenes, specifying different authentication types for each sets them up as different auth "engines". Here's how it looks in my Startup:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
        {
            OnResponseSignIn = ctx =>
            {
                ctx.Identity = TransformClaims(ctx, app);
            }
        }
});

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    Provider = new CookieAuthenticationProvider
    {
        OnResponseSignIn = ctx =>
        {
            ctx.Identity = TransformClaims(ctx, app);
        }
    }
});

app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
    Wtrealm = Realm,
    MetadataAddress = Metadata,
    Caption = "Active Directory",
    SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType
});

This is successfully allowing users to authenticate to either local SQL tables or to ADFS 2.0. The TransformClaims callout is allowing me to normalize my claims between these two providers so they are consistent.

EDIT: Here's a very rudimentary TransformClaims. You can do a lot of things inside this: get the user from your DB, setup claims for navigation, custom permissions, role collections, whatever. I just built this slimmed-down version from a much larger implementation so I've not run it but hopefully you get the idea of how to leverage the OnResponseSignIn event.

private static ClaimsIdentity TransformClaims(CookieResponseSignInContext ctx, IAppBuilder app)
{
    var ident = ctx.Identity;

    var claimEmail = ident.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Email);
    var claimName = ident.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Name);

    //normalize my string identifier
    var loginString = (claimEmail != null) ? claimEmail.Value : (claimName != null) ? claimName.Value : null;
    var efctx = ctx.OwinContext.Get<DBEntities>();

    var user = UserBL.GetActiveUserByEmailOrName(efctx, loginString);
    if (user == null)
    {
        //user was auth'd by ADFS but hasn't been auth'd by this app
        ident.AddClaim(new Claim(ClaimTypesCustom.Unauthorized, "true"));
        return ident;
    }

    if (ident.Claims.First().Issuer == "LOCAL AUTHORITY")
    {
        //Local
        //local already has claim type "Name"
        //local didn't have claim type "Email" - adding it
        ident.AddClaim(new Claim(ClaimTypes.Email, user.Email));
    }
    else
    {
        //ADFS
        //ADFS already has claim type "Email"
        //ADFS didn't have claim type "Name" - adding it
        ident.SetClaim(ClaimTypes.Name, user.UserName);
    }

    //now ident has "Name" and "Email", regardless of where it came from
    return ident;
}

Cmedine, based on Brett's answer i configured my authentication and authorization. I show you the code as you requested some sample code.

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            SlidingExpiration = false,
            CookieName = "identity",
            //short time for testing only
            ExpireTimeSpan = TimeSpan.FromSeconds(120),
            Provider = new CookieAuthenticationProvider
            {
                OnResponseSignIn = ctx =>
                {
                    ctx.Identity = TransformClaims(ctx);
                }
            }
        });

        app.UseWsFederationAuthentication(
            new WsFederationAuthenticationOptions
            {
                MetadataAddress = "https://[[ADFS_Url]]/FederationMetadata/2007-06/federationmetadata.xml",
                Wtrealm = "[[realm]]",
                UseTokenLifetime = false
            }
        );

    }

    private ClaimsIdentity TransformClaims(CookieResponseSignInContext ctx)
    {
        return new IdentityCreator().CreateIdentity(ctx.Identity, [[ApplicationName]]);
    }
}

The IdentityCreator takes the ClaimsIdentity and an Application name and goes to a DB and gets the claims for that user in that application. Hope it helps!!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!