Web API的基于角色的身份验证不起作用

时间:2020-09-02 13:47:42

标签: c# authentication asp.net-mvc-4 asp.net-web-api rbac

使用基于角色的Web APi身份验证时遇到问题。

我有一个控制器类,其中控制器具有一个称为Myauthorize的自定义授权属性。 我在控制器内部有一个方法,该方法只能通过管理员访问权限进行访问。 但是,同样的方法也已通过QA访问进行调用。 有人可以帮忙以下吗?

请在下面找到代码。 控制器:

namespace Hosiptal.Controllers.office
{
 [MyAuthorize(Constants.Roles.Admin)]
 public class UserRolesController : ApiController
 {
    private readonly IRepository<EntityModels.Role> rolesRepository;

    public UserRolesController(IRepository<EntityModels.Role> rolesRepository)
    {            
        this.rolesRepository = rolesRepository;
    }

    // GET: Users
    [HttpGet]
    [Route("")]        
    public IEnumerable<Role> GetAll()
    {
        return this.rolesRepository.GetAll()
            .ToArray()
            .Select(r => Mapper.Current.Get<Role>(r));                
    }
  }
}

MyAuthorize已遵循。

namespace Hospital.Web.Filters.WebApi
{

 public class MyAuthorize: AuthorizeAttribute
 {
    private readonly string[] allowedroles;
    private static IUserProfileRepository UserProfileRepository
    {
        get { return IoC.Current.Resolve<IUserProfileRepository>(); }
    }
    public MyAuthorize(params string[] roles)
    {
        this.allowedroles = roles;
    }

    public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken 
      cancellationToken)
    {
        var claimsIdentity = actionContext.RequestContext.Principal.Identity as ClaimsIdentity;
        
        var alias = claimsIdentity.Name.Split('@')[0];
        if (alias == null)
        {
            throw new ArgumentNullException(nameof(actionContext));
        }
        user(alias);
        return base.OnAuthorizationAsync(actionContext, cancellationToken);
    }

    public static GenericPrincipal user(string userName)
    {
        userName = userName.ToUpper();

        var userProfile = UserProfileRepository.Get(userName) ?? new UserProfile()
        {
            UserName = userName,
            Roles = new List<Role>(),
            FirstLoginDateUtc = DateTime.UtcNow
        };
        return CreatePrincipal(userProfile);
    }
    public static GenericPrincipal CreatePrincipal(UserProfile user)
    {
        var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, 
                           user.UserName) }, "Custom");
        return new GenericPrincipal(identity, user.Roles.Select(i => 
              i.Name).ToArray());
    }
   }
 }

如何根据访问级别在此处限制用户?

3 个答案:

答案 0 :(得分:1)

如果您查看AuthorizeAttribute类的the source code,您会发现它使用控制器上下文请求的主体执行授权,因此请改写IsAuthorized方法,将代码移到那里并将您创建的主体分配给上下文请求的主体:

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    var claimsIdentity = actionContext.RequestContext.Principal.Identity as ClaimsIdentity;

    var alias = claimsIdentity.Name.Split('@')[0];
    if (alias == null)
    {
        throw new ArgumentNullException(nameof(actionContext));
    }
    
    //This sets the context's principal so the base class code can validate
    actionContext.ControllerContext.RequestContext.Principal = user(alias);
    
    //Call the base class and let it work its magic
    return base.IsAuthorized(actionContext);
}

我将避免评论设计本身。这应该可以解决您的问题。

答案 1 :(得分:0)

这就是对我有用的

public class AdminAuthorizeAttributee : AuthorizeAttribute
{

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (AuthorizeRequest(actionContext))
        {
            return;
        }
        HandleUnauthorizedRequest(actionContext);
    }

    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        base.HandleUnauthorizedRequest(actionContext);
    }

    private bool AuthorizeRequest(HttpActionContext actionContext)
    {
        try
        {
            var username = HttpContext.Current.User.Identity.Name;
            var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
            var user = userManager.Users.Where(a => a.UserName == username).FirstOrDefault();
            var rolesForUser = userManager.GetRoles(user.Id);
            var role = "Admin";



            if (rolesForUser.Contains(role))
            {
                return true;
            }
            return false;
        }
        catch (Exception ex)
        {
            return false;
        }

    }

}

并在控制器中

[AdminAuthorizeAttributee]
public class YOUR_Controller : ApiController

答案 2 :(得分:0)

您无需为此创建自己的授权过滤器。 使用内置的[Authorize(Roles = "Admin")]-将检查用户是否有一个称为“ http://schemas.microsoft.com/ws/2008/06/identity/claims/role”的声明,并且该值是否与您输入的那个authorize属性中的一个,授权将成功。

因此,在您的情况下,请确保在登录用户时使用以下角色设置其主张:

            var claims = new List<Claim>()
            {
                new Claim(ClaimTypes.Role, "Admin"), //here set the users role
                     // ... other claims
            };

ClaimTypes类来自命名空间System.Security.Claims

然后[Authorize(Roles = "Admin")]应该可以正常工作