asp.net - 如何在不查找 AspNetUserRoles 表的情况下在 Web API 方法中获取用户角色?

标签 asp.net asp.net-mvc asp.net-web-api asp.net-identity asp.net-identity-2

我有一个更新状态的存储过程。根据用户的角色,存储过程的代码可能允许也可能不允许状态更改。为此,我需要将角色名称传递给存储过程。我的角色名称存储在我的 javascript 代码中的客户端上,但当然我需要在服务器上进行第二次检查。每个用户只有三个角色之一,当请求更新状态时,我可以根据客户端的角色调用三种方法之一。这是我尝试过的。

我正在使用 带有基于承载 token 的身份验证和 ASP.NET Identity 2.1 的 WebApi 并且该应用程序始终在浏览器中运行。我的用户已经设置了适当的角色。

我放置了一些代码来获取 userId,然后转到 AspNetUserRoles 表以获取方法开始时的角色。但是我注意到这需要大约 500 毫秒才能运行。作为替代方案,我正在考虑以下事项:

    [HttpPut]
    [Authorize(Roles = "Admin")]
    [Route("AdminUpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> AdminUpdateStatus(int userTestId, int userTestStatusId)
    {
        return await UpdateStatusMethod(userTestId, userTestStatusId, "Admin");
    }

    [HttpPut]
    [Authorize(Roles = "Student")]
    [Route("StudentUpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> StudentUpdateStatus(int userTestId, int userTestStatusId)
    {
        return await UpdateStatusMethod(userTestId, userTestStatusId, "Student");
    }

    [HttpPut]
    [Authorize(Roles = "Teacher")]
    [Route("TeacherUpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> TeacherUpdateStatus(int userTestId, int userTestStatusId)
    {
        return await UpdateStatusMethod(userTestId, userTestStatusId, "Teacher");
    }

    private async Task<IHttpActionResult> UpdateStatusMethod(int userTestId, int userTestStatusId, string roleName)
    {
        // Call the stored procedure here and pass in the roleName
    }

这是一种有效的方法,还是有另一种更干净的方法。我不太清楚的是前端还是后端缓存用户角色。我假设这已经完成,或者有一些设置允许这样做。

注意我在这里使用声明将角色信息发送给我的客户:
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);
        }

但是,我在这里的问题与服务器有关,以及如果用户在不访问数据库的情况下处于特定角色,我如何检查我的方法。也许有一种方法可以通过声明安全地做到这一点,但我不知道该怎么做。

任何帮助和建议将不胜感激。

最佳答案

正如您所说,您正在使用不记名 token 来保护您的端点。我相信对于那些不记名 token 魔法字符串包含在其中的内容几乎没有误解。
那么这些 token 包含您为其颁发 token 的用户的所有角色,以及如果您在 Web API 中使用默认数据保护 DPAPI 而不是(JWT token ),那么这些 token 将被签名和加密,因此没有人可以篡改数据在token里面除非他有mashineKey为web服务器发出这个token,所以不用担心数据保护。

我的建议是从数据库中读取用户的角色/声明,不需要你尝试做的这种变通方法和黑客,你需要做的就是在用户登录方法 GrantResourceOwnerCredentials 时为他们设置声明您可以通过获取用户然后从数据库读取角色并将它们设置为“角色”类型的声明来像这样设置它

 var identity = new ClaimsIdentity(context.Options.AuthenticationType);
 identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
 identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
 identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));

请记住,这仅在用户登录时发生一次,然后您将收到一个不记名签名和 ecrypted token ,其中包含该用户的所有声明,无需任何数据库访问来验证它。

或者,如果您想从数据库创建身份,您可以使用以下内容:
 public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
        // Add custom user claims here
        return userIdentity;
    }

然后在 GrantResourceOwnerCredentials 中执行以下操作:
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);

现在,一旦您将不记名 token 发送到具有 Authorize 属性(例如 [Authorize(Roles = "Teacher")])的 protected 端点,我可以向您保证您的代码不会去数据库执行任何查询,打开 SQL 探查器并检查它是否会从加密 token 中读取声明使用角色声明并检查此用户是否属于教师角色并允许或拒绝请求。

我在博客上写了 5 篇关于 Token Based Authentication 以及 Authorization serverJWT tokens 的详细系列文章。我建议您阅读这些帖子以更好地了解不记名 token 。

关于asp.net - 如何在不查找 AspNetUserRoles 表的情况下在 Web API 方法中获取用户角色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26589466/

相关文章:

asp.net-mvc - ASP.Net MVC - HTTP 状态代码(即 303、401、404 等)

c# - Web API 发布反序列化 json 结果但所有属性为空

c# - 在 IIS 中运行时出现 Swashbuckle 错误 - 404( 'swagger.json')

c# - Web 表单和 Web API 部署

asp.net - 查找所有未使用/引用的 ASP.NET 用户控件

c# - 如何在 jQuery 中获取 mvc c# 用户角色

asp.net - 在 ckeditor 中显示链接

javascript - 创建 div id concating 变量和字符串

ASP.Net Web 表单实体级访问控制

c# - 'OnCheckedChanged' 时 ASP.NET 更新网页