如何在不查找AspNetUserRoles表的情况下在WebAPI方法中获取用户角色?

Sam*_*tar 25 asp.net asp.net-mvc asp.net-web-api asp.net-identity asp.net-identity-2

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

我正在使用基于承载令牌的身份验证和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
    }
Run Code Online (Sandbox Code Playgroud)

这是一种有效的方法,或者是否有另一种更干净的方式.我不太清楚的是前端或后端是否缓存了用户角色.我认为这已经完成,或者有一些设置可以完成.

注意我在使用声明将角色信息发送到我的客户端:

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);
        }
Run Code Online (Sandbox Code Playgroud)

但是我的问题在这里与服务器有关,如果用户在没有进入数据库的情况下处于某个角色,我将如何检查我的方法.也许有一种方法可以安全地处理索赔,但我不知道该怎么做.

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

Tai*_*deh 34

如你所说,你使用持票人代币来保护你的终点.我相信对那些持有人令牌神奇的字符串包含在里面的东西几乎没有什么误解.那些令牌包含您为其颁发令牌的用户的所有角色,以及如果您使用Web API中的默认数据保护DPAPI(JWT令牌),那么这些令牌都经过签名和加密,因此没有人可以篡改数据在令牌内部,除非他为web服务器发出了这个令牌的mashineKey,所以不用担心数据保护.

我的建议是从数据库中读取用户的角色/声明,不需要这样的解决方法和你想要做的黑客攻击,你需要做的就是在用户登录时为用户设置声明GrantResourceOwnerCredentials你通过让用户然后从DB读取角色并将其设置为"角色"类型的声明,可以像这样设置它

 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"));
Run Code Online (Sandbox Code Playgroud)

请记住,只有在用户登录时才会发生这种情况,然后您将收到一个承载签名和ecrypted令牌,其中包含该用户的所有声明,无需任何数据库访问权限进行验证.

或者,如果要从数据库创建标识,可以使用以下内容:

 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;
    }
Run Code Online (Sandbox Code Playgroud)

然后在GrantResourceOwnerCredentials下面做:

ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);
Run Code Online (Sandbox Code Playgroud)

现在,一旦您将持有者令牌发送到具有Authorize属性的受保护端点,[Authorize(Roles = "Teacher")]我可以向您保证,您的代码将不会进入数据库进行任何查询打开SQL事件探查器并检查它是否将读取加密令牌中的声明以及角色声明并检查此用户是否属于教师角色并允许或拒绝该请求.

我在博客上发布了5篇关于基于令牌的身份验证以及授权服务器JWT令牌的详细系列文章.我建议你阅读这些帖子,以便更好地理解持票人令牌.


Exc*_*ted 9

您可以简单地检查User.IsInRole("RoleName")控制器类中的可用方法,而不是使用3个单独的方法.它使用[Authorise]属性中的相同逻辑.例如

public class DataApiController : ApiController
{
    [HttpPut]
    [Route("UpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> UpdateStatus(int userTestId, int userTestStatusId)
    {
        if(User.IsInRole("Admin"))
        {
            //Update method etc....
        }
        //else if(....) else etc
    {
}
Run Code Online (Sandbox Code Playgroud)

  • 取决于您的校长.如果您正在使用ClaimsPrincipal,那么不会,每个人都没有DB调用,因为它将从Claim获取角色. (3认同)
  • +1这是正确的答案.@Pleun Identity框架不会发出对DB进行角色检查的调用.请看郝公的回答. (2认同)