如何使用Asp.net webapi后端和前端在Azure中进行基于角色的授权作为Angular

问题描述:

如何在webapi后端中执行基于Azure角色的身份验证。我看到很多Asp.net MVC的例子,但没有一个用于Angular的前端webapi。我将我的网站作为webapi托管在后端,并将其托管在Azure上,并将身份验证/授权作为Azure网站中的Azure Active目录启用。此外,我已经完成AD应用程序的清单文件中的角色设置。在我访问网站后,我必须进行身份验证,然后在身份验证后重定向到我的网站。在我的网站加载期间,它会调用我的webapi,并将带有声明的身份验证令牌传递给我的webapi。在webapi中,我正在检查InRole或[Authorize(Roles =“admin”)],并基于我允许访问。但是,标记角色默认情况下不会流动。所以我通过从token中提取信息并将它传递给图api来获取角色来查询图api来获取角色。我在Owin Startup类中进行查询以获取角色,但我无法获得成功。代码有什么问题,请帮助。代码复制如下。此外,我可以在Angular中使用ADAL JS库来进行AD认证,但我不需要这样做,因为我已使用选项“认证/授权”在Azure网站中启用了身份验证。网站中的认证层将进行所有令牌验证并将其转发给webapi。如何使用Asp.net webapi后端和前端在Azure中进行基于角色的授权作为Angular

using System; 
using System.Collections.Generic; 
using System.Configuration; 
using System.IdentityModel.Tokens; 
using System.Linq; 
using Microsoft.Owin.Security; 
using Microsoft.Owin.Security.ActiveDirectory; 
using Owin; 
using System.Security.Claims; 
using System.Net; 
using System.Web; 
using System.IO; 
using System.Net.Http; 
using System.Net.Http.Headers; 
using Microsoft.IdentityModel.Clients.ActiveDirectory; 
using Microsoft.Owin.Security.OAuth; 
using Microsoft.Azure.ActiveDirectory.GraphClient; 
using System.Threading.Tasks; 

namespace OneMap.Web 
{ 
    public partial class Startup 
    { 
     // Apply bearer token authentication middleware to Owin IAppBuilder interface. 
     private void ConfigureAuth(IAppBuilder app) 
     { 
      var tenantId = Common.Configuration.GetConfigurationSetting("ida:Tenant"); 
      // ADAL authentication context for our Azure AD tenant. 
      var authenticationContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(
       $"https://login.windows.net/{tenantId}", true, TokenCache.DefaultShared); 

      // Secret key that can be generated in the Azure portal to enable authentication of a 
      // specific application (in this case our Web API) against an Azure AD tenant. 
      var applicationKey = Common.Configuration.GetConfigurationSetting("ida:Password"); 



      // Root URL for Azure AD Graph API. 
      var azureGraphApiUrl = "https://graph.windows.net"; 
      var graphApiServiceRootUrl = new Uri(new Uri(azureGraphApiUrl), tenantId); 
      var clientId = Common.Configuration.GetConfigurationSetting("ida:ClientId"); 
      // Add bearer token authentication middleware. 
      app.UseWindowsAzureActiveDirectoryBearerAuthentication(
       new WindowsAzureActiveDirectoryBearerAuthenticationOptions 
       { 
        // The id of the client application that must be registered in Azure AD. 
        TokenValidationParameters = new TokenValidationParameters { ValidAudience = clientId }, 
        // Our Azure AD tenant (e.g.: contoso.onmicrosoft.com). 
        Tenant = tenantId, 
        Provider = new OAuthBearerAuthenticationProvider 
        { 
         // This is where the magic happens. In this handler we can perform additional 
         // validations against the authenticated principal or modify the principal. 
         OnValidateIdentity = async context => 
           { 
            try 
            { 
           // Retrieve user JWT token from request. 
           var authorizationHeader = context.Request.Headers["Authorization"]; 
             var userJwtToken = authorizationHeader.Substring("Bearer ".Length).Trim(); 

           // Get current user identity from authentication ticket. 
           var authenticationTicket = context.Ticket; 
             var identity = authenticationTicket.Identity; 

           // Credential representing the current user. We need this to request a token 
           // that allows our application access to the Azure Graph API. 
           var userUpnClaim = identity.FindFirst(ClaimTypes.Upn); 
             var userName = userUpnClaim == null 
           ? identity.FindFirst(ClaimTypes.Email).Value 
           : userUpnClaim.Value; 
             var userAssertion = new UserAssertion(
           userJwtToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName); 

           // Credential representing our client application in Azure AD. 
           var clientCredential = new ClientCredential(clientId, applicationKey); 

           // Get a token on behalf of the current user that lets Azure AD Graph API access 
           // our Azure AD tenant. 
           var authenticationResult = await authenticationContext.AcquireTokenAsync(
           azureGraphApiUrl, clientCredential, userAssertion).ConfigureAwait(false); 

           // Create Graph API client and give it the acquired token. 
           var activeDirectoryClient = new ActiveDirectoryClient(
           graphApiServiceRootUrl,() => Task.FromResult(authenticationResult.AccessToken)); 

           // Get current user groups. 
           var pagedUserGroups = 
           await activeDirectoryClient.Me.MemberOf.ExecuteAsync().ConfigureAwait(false); 
             do 
             { 
            // Collect groups and add them as role claims to our current principal. 
            var directoryObjects = pagedUserGroups.CurrentPage.ToList(); 
              foreach (var directoryObject in directoryObjects) 
              { 
               var group = directoryObject as Group; 
               if (group != null) 
               { 
              // Add ObjectId of group to current identity as role claim. 
              identity.AddClaim(new Claim(identity.RoleClaimType, group.ObjectId)); 
               } 
              } 
              pagedUserGroups = await pagedUserGroups.GetNextPageAsync().ConfigureAwait(false); 
             } while (pagedUserGroups != null); 
            } 
            catch (Exception e) 
            { 
             throw; 
            } 
           } 
        } 
       }); 
     } 
    } 
} 

AFAIK,roles索赔只在id_token中发布。在更改应用程序清单(请参阅here)之后,您可以使用SPA获取id_token,并根据角色通过id_token访问Web API。

由于您使用Microsoft.Owin.Security.ActiveDirectory OWIN中间件保护了Web API,因此不需要使用认证/授权。要认证SPA,你可以参考这个code sample

+0

谢谢菲求救。我试图使用认证/授权,而不是使用Angular ADAL库,我想为什么我应该编写额外的代码,如果一切都在这里提供,但在这个角色索赔不来。正如你所说,它只会在id_token中出现,我将为角度实现ADAL。所以有两种类型的令牌(Access令牌和id_token)。我希望我会使用角色adal库得到ID_Token? –

+0

当我们通过启用身份验证/授权功能来保护网络应用程序时,我们可以使用由** easy auth **发布的cookie和令牌来调用网络API。无法使用Azure AD发布的id_token调用Web API。在这种情况下,它不支持角色声明。正确的解决方案是使用OWIN组件保护Web API,并使用角色adal库获取包含角色信息的id_token,并使用此令牌调用We​​b API。 –