Angularjs Adal和其他声明或授权属性 [英] Angularjs Adal and additional claims or properties for Authorization

查看:115
本文介绍了Angularjs Adal和其他声明或授权属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景是带有c#WebApi的Angularjs 1.6.5应用程序。使用 angular-adal.js AAD 进行身份验证。到目前为止,一切都运行良好,因为用户可以通过AAD登录并且WebApi接受令牌。



对于此特定应用程序,角色位于WebApi有权访问的外部应用程序中。我已经能够使用 WindowsAzureActiveDirectoryBearerAuthenticationOptions 并在 ConfigureOAuth( IAppBuilder应用)

  app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters =新的System.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudience = clientId
},
// Audience = ConfigurationManager.AppSettings [ ida:ClientID] ,
租户=租户,


提供者=新的OAuthBearerAuthenticationProvider
{
OnValidateIdentity =异步上下文=>
{
//从请求中检索用户JWT令牌。
varauthorizationHeader = context.Request.Headers [ Authorization];
var userJwtToken = authorizationHeader.Substring( Bea rer .Length).Trim();

//从身份验证票获取当前用户身份。
var authenticationTicket = context.Ticket;
var identity = authenticationTicket.Identity;

if(identity.FindFirst(System.Security.Claims.ClaimTypes.Role)== null)
{
var user = identity.FindFirst( http:// schemas .xmlsoap.org / ws / 2005/05 / identity / claims / upn)。值;

Cis.bll.Xrm.bllSystemUserRoles bllSystemUserRoles =新的Cis.bll.Xrm.bllSystemUserRoles();
var su = bllSystemUserRoles.getByEmail(user);
// var roleClaim = new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role,su.stringRoles);
foreach(su.Roles中的变量)
{
identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role,item.xrmName)) ;
}
}
}
}
});

因此,对于Angularjs对API所做的每个httpRequest,上一个函数都会为用户查找角色并添加角色声明。通过此实现,我可以在Controller方法中使用AuthorizeAttribute,将访问权限限制为仅某些角色,例如:

  [ CustomAuthorize(Constants.Roles.resourcesAdministrator)] 

我发现这种方式效率很低,因为对于每个httpRequest, API必须从数据库中获取用户角色(或采用任何持久方式)。



我要做的就是只读取一次用户角色,然后可以在每个后续请求中在API中使用它们。在我们收到针对AAD的令牌之后,是否可以将声明添加到令牌中?



顺便说一句,我可以只向每个模型添加Roles属性,或类似的东西,但这不是我想要的。



如果您还有其他想法或建议,将不胜感激。



致谢

解决方案

该令牌自发行以来就无法修改。而且由于角色存储在另一个应用程序中,所以我认为不查询数据库就不可能获得角色。



在这种情况下,我们可以管理通过Azure AD应用程序角色&角色声明。然后它将在id_token中发出 roles 声明。



例如,我们可以修改应用的清单,如下所示:

  appRoles:[
{
allowedMemberTypes:[
User
],
displayName: Writer,
id: d1c2ade8-98f8-45fd-aa4a-6d06b947c66f,
isEnabled:true,
description:作者具有创建任务的能力。,
value: Writer
},
{
allowedMemberTypes:[
User
],
displayName:观察者,
id: fcac0bdb-e45d-4cfc-9733-fbea156da358,
isEnabled:true,
description:观察者只能查看任务和它们的状态。,
值:观察者
},
{
allowedMemberTypes:[
用户
],
displayName:批准者,
id: fc803414-3c61-4ebc-a5e5-cd1675c14bbb,
isEnabled:true,
de scription:批准者可以更改任务状态。,
value:批准者
},
{
allowedMemberTypes:[
用户
],
displayName:管理员,
id: 81e10148-16a8-432a-b86d-ef620c3e48ef,
isEnabled :true,
描述:管理员可以管理角色并执行所有任务操作。,
value:管理员
}
],

并通过Azure门户通过应用程序将角色分配给用户,如下图:


Scenario is Angularjs 1.6.5 app with a c# WebApi. Authentication is done against AAD with the use of angular-adal.js. Up to now, everything Works perfectly, as users are able to login through AAD and WebApi accepts the token.

For this specific app, the roles are in an External application, to which the WebApi has Access. I have been able to add the role claims (after fetching them from the External app) with the use of WindowsAzureActiveDirectoryBearerAuthenticationOptions with the following code inside the ConfigureOAuth(IAppBuilder app):

app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
   TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
   {
       ValidAudience = clientId
   },
   //Audience = ConfigurationManager.AppSettings["ida:ClientID"],
   Tenant = tenant,


   Provider = new OAuthBearerAuthenticationProvider
   {
       OnValidateIdentity = async context =>
     {
         // 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;

         if (identity.FindFirst(System.Security.Claims.ClaimTypes.Role) == null)
         {
             var user = identity.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn").Value;

             Cis.bll.Xrm.bllSystemUserRoles bllSystemUserRoles = new Cis.bll.Xrm.bllSystemUserRoles();
             var su = bllSystemUserRoles.getByEmail(user);
             //var roleClaim = new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, su.stringRoles);
             foreach (var item in su.Roles)
             {
                 identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, item.xrmName));
             }
         }
     }
   }
});

So for each httpRequest that Angularjs does to the API, the previous function looks up the roles for the user and adds the role claims. With this implementation, I am able to use an AuthorizeAttribute in the Controller methods, restricting Access to only certain roles like so:

[CustomAuthorize(Constants.Roles.resourcesAdministrator)]

I find this way highly inneficient, because with each httpRequest, the API has to fetch the roles of the user from the database (or whatever persistance way is implemented).

What I want to do is to read the user roles just once, and then be able to use them in the API with every subsequent request. Is there a way to add the claims to the token AFTER we recieve the token for AAD?

BTW, I could just add a Roles property to each model, or something like that, but it is not what I'm looking for.

If you have any other ideas or suggestions, they will be greatly appreciated.

Regards

解决方案

The token is not able to modified since it is issued. And since the roles is stored in the other application, I don't think it is possible to get the roles without query the database.

In this scenario, we can manage the roles though the Azure AD application roles & role claims. Then it will issue the roles claim in the id_token.

For example, we can modify the manifest of the app like below:

"appRoles": [
    {
      "allowedMemberTypes": [
        "User"
      ],
      "displayName": "Writer",
      "id": "d1c2ade8-98f8-45fd-aa4a-6d06b947c66f",
      "isEnabled": true,
      "description": "Writers Have the ability to create tasks.",
      "value": "Writer"
    },
    {
      "allowedMemberTypes": [
        "User"
      ],
      "displayName": "Observer",
      "id": "fcac0bdb-e45d-4cfc-9733-fbea156da358",
      "isEnabled": true,
      "description": "Observers only have the ability to view tasks and their statuses.",
      "value": "Observer"
    },
    {
      "allowedMemberTypes": [
        "User"
      ],
      "displayName": "Approver",
      "id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
      "isEnabled": true,
      "description": "Approvers have the ability to change the status of tasks.",
      "value": "Approver"
    },
    {
      "allowedMemberTypes": [
        "User"
      ],
      "displayName": "Admin",
      "id": "81e10148-16a8-432a-b86d-ef620c3e48ef",
      "isEnabled": true,
      "description": "Admins can manage roles and perform all task actions.",
      "value": "Admin"
    }
  ],

And assign the roles to the user through the application via Azure portal like figure below:

Then we can get the id_token like request below(implicit grant flow), the roles should be in the token. And we can call the web API using this token.

Get:https://login.microsoftonline.com/{tenant}/oauth2/authorize?response_type=id_token&client_id={clientId}&redirect_uri={redirect_uri}&nonce={nonce}

id_token sample:

这篇关于Angularjs Adal和其他声明或授权属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆