asp.net mvc上的自定义授权属性

本文关键字:自定义 授权 属性 net mvc asp | 更新日期: 2023-09-27 17:51:11

我有一个asp.net mvc应用程序,它通过Azure AAD进行授权。该应用程序基于以下github示例:

https://github.com/dushyantgill/VipSwapper/tree/master/TrainingPoint

该应用程序具有自定义授权属性

  public class AuthorizeUserAttribute : AuthorizeAttribute
  {
        protected override void HandleUnauthorizedRequest(AuthorizationContext ctx)
        {
            if (!ctx.HttpContext.User.Identity.IsAuthenticated)
                base.HandleUnauthorizedRequest(ctx);
            else
            {
                ctx.Result = new ViewResult { ViewName = "Error", ViewBag = { message = "Unauthorized." } };
                ctx.HttpContext.Response.StatusCode = 403;
            }
        }
    }

然而,这对我来说似乎很奇怪。

我在控制器上有这样的东西:

 public class GlobalAdminController : Controller
    {
        // GET: GlobalAdmin
        [AuthorizeUser(Roles = "admin")]
        public ActionResult Index()
        {
            return View();
        }
    }

正如您所看到的,这里使用了自定义属性,但请深入查看自定义属性的代码。显然,在if和ELSE上,请求都没有经过身份验证。

现在看一下这个屏幕截图。

毫无意义,对吧?http://screencast.com/t/obqXHZJj0iNG

问题是,我应该怎么做才能允许用户执行控制器?

更新1:在我的身份验证流上,我有以下

  public void ConfigureAuth(IAppBuilder app)
        {
            // configure the authentication type & settings
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            // configure the OWIN OpenId Connect options
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = SettingsHelper.ClientId,
                Authority = SettingsHelper.AzureADAuthority,
                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    // when an auth code is received...
                    AuthorizationCodeReceived = (context) => {
                        // get the OpenID Connect code passed from Azure AD on successful auth
                        string code = context.Code;
                        // create the app credentials & get reference to the user
                        ClientCredential creds = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret);
                        string userObjectId = context.AuthenticationTicket.Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value;
                        // use the ADAL to obtain access token & refresh token...
                        //  save those in a persistent store...
                        EfAdalTokenCache sampleCache = new EfAdalTokenCache(userObjectId);
                        AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority, sampleCache);
                        // obtain access token for the AzureAD graph
                        Uri redirectUri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
                        AuthenticationResult authResult = authContext.AcquireTokenByAuthorizationCode(code, redirectUri, creds, SettingsHelper.AzureAdGraphResourceId);
                        if (GraphUtil.IsUserAADAdmin(context.AuthenticationTicket.Identity))
                            context.AuthenticationTicket.Identity.AddClaim(new Claim("roles", "admin"));
                        // successful auth
                        return Task.FromResult(0);
                    },
                    AuthenticationFailed = (context) => {
                        context.HandleResponse();
                        return Task.FromResult(0);
                    }
                },
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuer = false
                }
            });
        }

特别检查IsAADAdmin方法调用

/// <summary>
        /// The global administrators and user account administrators of the directory are automatically assgined the admin role in the application.
        /// This method determines whether the user is a member of the global administrator or user account administrator directory role.
        /// RoleTemplateId of Global Administrator role = 62e90394-69f5-4237-9190-012177145e10
        /// RoleTemplateId of User Account Administrator role = fe930be7-5e62-47db-91af-98c3a49a38b1
        /// </summary>
        /// <param name="objectId">The objectId of user or group that currently has access.</param>
        /// <returns>String containing the display string for the user or group.</returns>
        public static bool IsUserAADAdmin(ClaimsIdentity Identity)
        {
            string tenantId = Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
            string signedInUserID = Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value;
            string userObjectID = Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret);
            // initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
            AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority, new EfAdalTokenCache(signedInUserID));
            AuthenticationResult result = authContext.AcquireTokenSilent(
                SettingsHelper.AzureAdGraphResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
            HttpClient client = new HttpClient();
            string doQueryUrl = string.Format("{0}/{1}/users/{2}/memberOf?api-version={3}",
                SettingsHelper.AzureAdGraphResourceId, tenantId,
                userObjectID, SettingsHelper.GraphAPIVersion);
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, doQueryUrl);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = client.SendAsync(request).Result;
            if (response.IsSuccessStatusCode)
            {
                var responseContent = response.Content;
                string responseString = responseContent.ReadAsStringAsync().Result;
                var memberOfObjects = (System.Web.Helpers.Json.Decode(responseString)).value;
                if (memberOfObjects != null)
                    foreach (var memberOfObject in memberOfObjects)
                        if (memberOfObject.objectType == "Role" && (
                            memberOfObject.roleTemplateId.Equals("62e90394-69f5-4237-9190-012177145e10", StringComparison.InvariantCultureIgnoreCase) ||
                            memberOfObject.roleTemplateId.Equals("fe930be7-5e62-47db-91af-98c3a49a38b1", StringComparison.InvariantCultureIgnoreCase)))
                            return true;
            }
            return false;
        }

我100%确信用户是管理员,因为当我调试时,它返回true,并且声明是创建的

更新2:在调试时,我检查了User.Claims,角色admin就在那里。所以我不确定每个角色的授权是如何与User.IsInRole 一起工作的

http://screencast.com/t/zUbwbpzn55qb

asp.net mvc上的自定义授权属性

Esteban,您似乎错过了在ConfigureAuth实现中设置角色声明类型。请参阅样本的第55行:https://github.com/dushyantgill/VipSwapper/blob/master/TrainingPoint/App_Start/Startup.Auth.cs#L55.完成该操作后,User.IsInRole((和Authorize属性将正常工作。

Regd自定义Authorize属性的实现-ASP.net有一个错误,它在授权失败时返回401错误(而不是403((这将使经过身份验证的用户与IdP处于无休止的身份验证循环中(。此自定义authorize属性修复了该问题。

希望能有所帮助。

再见。

角色的声明类型为http://schemas.microsoft.com/ws/2008/06/identity/claims/role(您可以根据此处使用ClaimTypes.Role的快捷方式(。

我认为你的ConfigureAuth类应该从这个改为:

if (GraphUtil.IsUserAADAdmin(context.AuthenticationTicket.Identity))
                            context.AuthenticationTicket.Identity.AddClaim(new Claim("roles", "admin"));

对此:

if (GraphUtil.IsUserAADAdmin(context.AuthenticationTicket.Identity))
                            context.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));