【问题标题】:How can I find the content of a claim from inside an ASP.NET Web API method?如何从 ASP.NET Web API 方法中找到声明的内容?
【发布时间】:2014-11-20 19:40:52
【问题描述】:

在我的代码 (ASP.NET Identity 2.1) 中,我将声明设置如下:

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
        ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }
        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);
        ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
            CookieAuthenticationDefaults.AuthenticationType);
        AuthenticationProperties properties = CreateProperties(
            user.UserName,
            oAuthIdentity,
            user.FirstName,
            user.LastName,
            user.Organization);
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
        context.Request.Context.Authentication.SignIn(cookiesIdentity);
    }

这里是 CreateProperites 方法,然后添加角色声明:

    public static AuthenticationProperties CreateProperties(
        string userName,
        ClaimsIdentity oAuthIdentity,
        string firstName,
        string lastName,
        int organization)
    {

        IDictionary<string, string> data = new Dictionary<string, string>
            {
                { "userName", userName},
                { "firstName", firstName},
                { "lastName", lastName},
                { "organization", organization.ToString()},
                { "roles",string.Join(":",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())}

            };
        return new AuthenticationProperties(data);
    }

在我的客户端上,我发出一个令牌请求并像这样接收它:

    this.$http({
        method: 'POST',
        url: '/Token',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password),
    })
        .success((data: any, status, headers, cfg) => {
            self.data.roles = data.roles;

我可以看到 self.data.roles 正确填充了角色。现在回到服务器上,我想检查角色声明的内容。有人可以告诉我如何做到这一点吗?我知道我可以在方法中执行以下操作:

    [HttpGet]
    [Route("Retrieve")]
    public async Task<IHttpActionResult> Retrieve()
    {

        var x = User;

x 获取

的值
System.Security.Claims.ClaimsPrinciple and 
System.Security.Claims.ClaimsIdentity

但在 x 内,我无法找到有关索赔本身的信息。

请注意,我确实尝试过之前在 SO 上发布的建议:

        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;

        // The following line returns null
        var roles = identity.Claims.Where(r => r.Type == "roles").FirstOrDefault();

但我仍然无法在声明中找到与 角色 声明相关的信息。我知道它必须在它到达客户时就在那里。

请注意,我正在寻找“角色”声明。不是任何系统生成的声明。但是我尝试添加自己的一个包含角色的串联列表。

【问题讨论】:

    标签: asp.net asp.net-web-api asp.net-identity claims-based-identity


    【解决方案1】:

    你试过了吗?

    var roleClaims = identity.Claims.Where(c =&gt; c.Type == ClaimTypes.Role);

    更新

    首先,您没有添加声明。您正在将一些数据添加到AuthenticationTicket 的属性字典中。此数据恰好是逗号分隔的角色,您选择命名的键是“角色”。所以,这不是索赔。

    当你说它对我不起作用时,我相信你想找到你放在字典中的逗号分隔值。如果是这种情况,您无法从控制器中的User 检索它。当您发送不记名令牌时,不记名令牌身份验证中间件会读取令牌,从令牌中获取ClaimsIdentity 并将其设置在上下文中,以便您可以从User 中读取它。

    您放入AuthenticationTicket 的任何内容都供中间件(实际上是处理程序)使用。所以,如果你想从AuthenticationTicket获取任何数据,你需要自己在承载中间件上调用AuthenticateAsync。通过执行var result = await AuthenticationManager.AuthenticateAsync(OAuthDefaults.AuthenticationType);,您现在可以获得整张票,而不仅仅是ClaimsIdentity。通过查看result,您应该能够获得逗号分隔的角色,但随后会明白,承载中间件已经为您完成了一次,您正在再次调用它。

    顺便说一句,如果要添加自定义声明,则需要将其添加到 GrantResourceOwnerCredentials 中的 oAuthIdentity

    public override async Task GrantResourceOwnerCredentials(
                                OAuthGrantResourceOwnerCredentialsContext context)
    {
        // snip
        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
               OAuthDefaults.AuthenticationType);
        oAuthIdentity.AddClaim(new Claim("urn:roles", "a,b,c");
    }
    

    如果你这样做,你可以从User阅读。

    var myRoleClaims = identity.Claims.Where(c =&gt; c.Type == "urn:roles");

    【讨论】:

    • 这对我不起作用。我想找到我自己添加的声明的内容,而不是添加了 ClaimTypes.Role 的内容。谢谢。
    • 感谢您的建议。我真的希望有更多的例子。我花了很多时间查看不同的网络链接,但没有找到任何最近的东西,而且技术变化如此之快,我很难跟上。
    【解决方案2】:

    我认为问题在于您正在查看错误的身份验证类型,User.Identity 映射到 cookie 和“活动”身份验证类型,即:CookieAuthenticationDefaults.AuthenticationType

    要查看您的角色的 claimIdentity,您可能需要调用 IAuthenticationManager.Authenticate(OAuthDefaults.AuthenticationType) 然后我认为您会看到您期望的 roleClaims。

    编辑:添加示例

        var result = await AuthenticationManager.AuthenticateAsync(OAuthDefaults.AuthenticationType);
        // do something with result.Identity
    

    【讨论】:

    • 你能给我一个例子,说明我需要在哪里调用它。我需要把它放在控制器中吗?如果您能给我一个 3-4 行代码示例,那么我可以尝试一下。谢谢。
    • 当然,您应该能够在控制器中执行类似的操作以获取声明身份
    • 会进入数据库吗?我希望将“角色”声明发送到浏览器,然后每次都将其返回到服务器,让我可以获取但不能从数据库获取?
    • 不,它不会进入数据库,它只会访问您为 authtype 配置的任何 auth 中间件,即您的 OAuth.AuthenticationType 中间件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 2013-08-16
    • 2019-03-31
    相关资源
    最近更新 更多