Asp.net web api 认证/授权MVC 5和Web API-Katana/Owin

Asp.net web api 认证/授权MVC 5和Web API-Katana/Owin,asp.net-web-api,owin,adfs,katana,Asp.net Web Api,Owin,Adfs,Katana,我在决定一个项目的路线时遇到了问题 我一直在阅读OWIN规范和.NET中的Katana实现。我之所以选择Katana路线,是因为与ADF和令牌/Cookie生成相关联的owin组件 我有两个项目,一个是MVC5网站,一个是Web API。将来它们可能会在两个独立的服务器上休息,但现在它们在同一台服务器上 我知道我将使用IIS,因此Owin管道对我来说没有必要进行调查 我的要求是,将有使用ADF登录的用户,以及使用令牌/Cookie生成、角色/成员身份提供程序登录的其他用户。根据谁经过身份验证,我

我在决定一个项目的路线时遇到了问题

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

我有两个项目,一个是MVC5网站,一个是Web API。将来它们可能会在两个独立的服务器上休息,但现在它们在同一台服务器上

我知道我将使用IIS,因此Owin管道对我来说没有必要进行调查

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

有没有人有我可以通读的材料来帮助解释我可以采用的设计流程?或者有人做过类似于我正在经历的项目,可以添加任何建议?有很多不同的文档描述了我需要的具体东西,但不是大局;比如只谈论WebAPI和adf,或者WebAPI和windowsazure等等

我的理论是在MVC5网站项目上实现身份验证/授权,在Web API上实现授权(两者之间需要存在某种通信)。然后我可能会为ADF创建一个项目副本,为令牌/cookie身份验证创建另一个副本?或者,我可能需要进行4种不同的身份验证:2种用于ADF,其中我根据MVC5网站和Web API进行身份验证,另外2种用于生成令牌/cookie


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

我可以提供OWIN中的WsFederation选项很好,但需要cookies…而且它们是一种不同于具有cookies的本地身份验证的cookie。ADFS 2.0/WsFederation使用AuthenticationType=“Cookies”,本地身份验证使用AuthenticationType=“ApplicationCookie”。据我所知,它们显然是不相容的。我认为您将不得不为ADFS使用令牌身份验证,但我相信这需要在2012年2月2日使用ADFS 3.0。在OAuth中使用

更新:经过一段时间的研究,我已经找到了如何让这两种身份验证类型在同一个web应用程序中和平共存的方法。使用OWIN,设置为调用UseCookieAuthentication两次,一次启用新的WsFederationAuthentication中间件,另一次启用本地cookie身份验证。这不是直观的,而是在幕后,为每种类型指定不同的身份验证类型将它们设置为不同的身份验证“引擎”。以下是我的初创公司的情况:

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 callout允许我规范这两个提供者之间的声明,以便它们保持一致

编辑:这里有一个非常基本的观点。您可以在这里面做很多事情:从数据库中获取用户、设置导航声明、自定义权限、角色集合等等。我刚刚从一个更大的实现中构建了这个精简版本,所以我没有运行它,但希望您了解如何利用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;
}
private static ClaimsIdentity TransformClaims(CookiierResponseSigninContext ctx,IAppBuilder应用程序)
{
var ident=ctx.Identity;
var claimEmail=ident.Claims.SingleOrDefault(c=>c.Type==ClaimTypes.Email);
var claimName=ident.Claims.SingleOrDefault(c=>c.Type==ClaimTypes.Name);
//规范化我的字符串标识符
var loginString=(claimEmail!=null)?claimEmail.Value:(claimName!=null)?claimName.Value:null;
var efctx=ctx.OwinContext.Get();
var user=UserBL.GetActiveUserByEmailOrName(efctx,loginString);
if(user==null)
{
//用户已通过ADFS验证,但尚未通过此应用验证
标识添加索赔(新索赔(索赔类型为“未经授权,真实”);
返回标识;
}
if(ident.Claims.First().Issuer==“地方当局”)
{
//本地的
//本地已具有声明类型“Name”
//本地没有索赔类型“电子邮件”-正在添加
标识AddClaim(新索赔(ClaimTypes.Email,user.Email));
}
其他的
{
//ADF
//ADFS已具有索赔类型“电子邮件”
//ADFS没有索赔类型“Name”-添加它
标识SetClaim(ClaimTypes.Name,user.UserName);
}
//现在ident有“Name”和“Email”,不管它来自哪里
返回标识;
}

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和一个应用程序名,然后转到数据库,获取该应用程序中该用户的声明。希望能有帮助

哇,这帮了我很多忙!谢谢嗨,Brett,你能给我举个TransformClaims函数的例子吗?我正在尝试将我的安全基础设施迁移到owin/katana,但我还是有点迷茫。我想在身份验证之后立即从数据库中获取所有用户声明,并将所有声明放在缓存的cookie中一小时。有这样的吗?谢谢!!Brett,谢谢你发布代码,非常有用。声明转换是否可以在cookie中缓存一定的时间,并且在该时间过后,声明转换会根据请求再次运行,从而再次从DB获得权限?谢谢我不是100%确定,但我相信这将是ADFS中令牌超时设置的一个功能。一旦您最初通过身份验证,您转换或添加的声明将在刷新时跟随您,直到身份验证令牌过期,在下一次刷新时,站点将检测到您的令牌无效,您将