身份验证/授权MVC 5和Web API - Katana / Owin

时间:2014-04-08 16:10:08

标签: asp.net-web-api owin adfs katana

我在尝试决定我的项目路线时遇到了问题。

我一直在阅读.NET中的OWIN规范和Katana实现。我之所以选择Katana路由,是因为与ADFS和令牌/ Cookie生成相关的owin组件。

我有两个项目,一个用于MVC 5网站,另一个用于Web API。它们将来可能会停留在两台独立的服务器上,但现在它们是相同的。

我知道我将使用IIS,因此我无需调查Owin管道。

我的要求是将有使用ADFS登录的用户,以及将使用角色/成员资格提供程序使用令牌/ Cookie生成登录的其他用户。根据谁进行身份验证,我的网页的某些部分将被公开。网页工程师在剃须刀中完成。

有没有人有任何我可以阅读的材料来帮助解释我可以采取的设计流程?或者任何人都做了一个类似于我正在经历的项目,可以添加任何建议?有很多不同的文件描述了我需要的特定事物,但不是大局;比如只谈论WebAPI和ADFS,或者WebAPI和windows azure等等。

我的理论是在MVC5网站项目上实现认证/授权,在Web API上进行授权(两者之间需要以某种方式进行通信)。然后,我可能为ADFS创建项目的副本,并为令牌/ cookie身份验证创建另一个副本?或者我可能需要进行4种不同的身份验证:2对于我在MVC5网站和Web API上进行身份验证的adfs,以及另外2次用于令牌/ cookie生成的身份验证。

任何建议都会有所帮助,因为我对这种技术不是很熟悉。

2 个答案:

答案 0 :(得分:9)

我可以提供OWIN中的WsFederation选项很好但需要cookie ...而且它们与使用cookie的本地身份验证不同。 ADFS 2.0 / WsFederation使用AuthenticationType =" Cookies",本地身份验证使用AuthenticationType =" ApplicationCookie"。就我所知,它们显然是不相容的。我认为您必须为ADFS使用令牌身份验证,但我相信在2012R2上需要ADFS 3.0。为此使用OWIN OAuth。

更新:经过一段时间的努力,我已经弄清楚如何让这两种身份验证类型在同一个Web应用程序中和平共存。使用OWIN,设置调用UseCookieAuthentication TWICE,一次启用新的WsFederationAuthentication中间件,再次启用本地cookie身份验证。它不直观但在幕后,为每个指定不同的身份验证类型将它们设置为不同的auth"引擎"。以下是我在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
});

这成功地允许用户对本地SQL表或ADFS 2.0进行身份验证。 TransformClaims标注允许我规范化这两个提供者之间的声明,使它们保持一致。

编辑:这是一个非常基本的TransformClaims。你可以在其中做很多事情:从你的数据库中获取用户,设置导航声明,自定义权限,角色集合等等。我刚从更大的实现中构建了这个精简版本,所以我没有运行它,但希望你能够了解如何利用OnResponseSignIn事件。

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;
}

答案 1 :(得分:1)

Cmedine,根据Brett的回答,我配置了我的身份验证和授权。我向您展示了您请求一些示例代码的代码。

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]]);
    }
}

IdentityCreator获取ClaimsIdentity和应用程序名称并转到数据库并获取该应用程序中该用户的声明。希望它有所帮助!!