简体   繁体   中英

How to do Azure AD groups authorization in .Net core web API?

Net core web application. I am trying to implement groups based authorization in my .Net core app. I am trying to call groups from Microsoft graph. I have some confusion here. Below are the steps.

  1. Created Web API app in .Net core 2.1
  2. Added swashbuckle swagger support to it.
  3. created app in Azure AD for swagger
  4. Created app in Azure AD for back end .Net core API (Name is WebServicesAPP).
  5. In WebServicesAPP app -> Expose an API-> Add client application -> Added my swagger app.
  6. In WebServicesAPP app -> API Permissions -> Add Permission -> Microsoft graph API -> Application Permission -> Group.ReadAll
  7. changed Oauthimplicitflow to True in manifest.

These are the steps I taken. After this I have added relevant code to implement swagger as below. In startup I have added

public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services
               .AddAuthentication(o =>
               {
                   o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;

               })
               .AddJwtBearer(o =>
               {
                   o.Authority = azureActiveDirectoryOptions.Authority;

                   o.TokenValidationParameters = new TokenValidationParameters
                   {

                       ValidAudiences = new List<string>
                       {
                          azureActiveDirectoryOptions.AppIdUri,
                          azureActiveDirectoryOptions.ClientId
                       },
                       ValidateIssuer = true
                   };
               });
            services.AddScoped<IAuthorizationHandler, GroupsCheckHandler>();
            services.AddAuthorization(options =>
            {   
                options.AddPolicy("GroupsCheck", policy =>
                {
                    policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
                    policy.RequireAuthenticatedUser();
                    policy.Requirements.Add(new GroupsCheckRequirement("9da02036-fc14-4e97-ac58-2293bddae44d"));
                });
            });
            services.AddMvc(options =>
            {

                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });

                c.AddSecurityDefinition("oauth2", new OAuth2Scheme
                {
                    Type = "oauth2",
                    Flow = "implicit",
                    AuthorizationUrl = swaggerUIOptions.AuthorizationUrl,
                    TokenUrl = swaggerUIOptions.TokenUrl
                });
                c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
                {
                        { "oauth2", new[] { "readAccess", "writeAccess" } }
                });
            });
        }


        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
            app.UseHttpsRedirection();

            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {

                c.OAuthClientId(swaggerUIOptions.ClientId);
                c.OAuthClientSecret(swaggerUIOptions.ClientSecret);
                c.OAuthRealm(azureActiveDirectoryOptions.ClientId);
                c.OAuthAppName("Swagger");
                c.OAuthAdditionalQueryStringParams(new { resource = azureActiveDirectoryOptions.ClientId });
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            });
            app.UseAuthentication();
            app.UseMvc();
        }

Now with my above code I am generating swagger. In swagger I clicked on Authorize Tab-> Added my login details and I tried to hit below sample API.

 [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase

With Application permission and client credential I am using below code to get token for MS graph

AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(graphResource, clientCred).ConfigureAwait(false);
            var token = authenticationResult.AccessToken;

Once I get toke from above code I am successfully getting groups like below

GraphServiceClient client = await MicrosoftGraphClient.GetGraphServiceClient();
            var groupList = await client.Users[userId].MemberOf.Request().GetAsync(); 

I am able to hit API and I am having no issue.

Now I want to get all the groups from Microsoft graph API end point. I need little clarification on below.

  1. Now I already have token and can I use same token to call Microsoft graph API?
  2. Now I am trying to get current logged in users group so when adding Microsoft graph we have two options delegated permission and application permission. delegated permission -> Used to call graph API on behalf of user Application permission -> App itself calls Microsoft graph API. Using client credentials flow It generates token and passes to Microsoft graph and authenticates.
  3. In my case I have logged in user ad I am trying to hit Microsoft graph. So which One I should use Delegated Permission or Application Permission?

I am finding very hard to understand these since quite time and I do not see any relevant document for my approach. Can someone help me to understand this? Really any suggestions will really help me. Thanks a lot.

Now I already have token and can I use same token to call Microsoft graph API?

No. The token is for your API. You need to get another token for MS Graph API using eg the MSAL library ( https://www.nuget.org/packages/Microsoft.Identity.Client/ ).

Now I am trying to get current logged in users group so when adding Microsoft graph we have two options delegated permission and application permission. delegated permission -> Used to call graph API on behalf of user Application permission -> App itself calls Microsoft graph API. Using client credentials flow It generates token and passes to Microsoft graph and authenticates.

In my case I have logged in user ad I am trying to hit Microsoft graph. So which One I should use Delegated Permission or Application Permission?

It's a good question. Either will most likely work. I tend to prefer delegated permissions whenever possible, as that limits the scope of things my app can access.

Application permissions are typically easier to use, but grant your app tenant-wide access. Since the token acquired with app permissions is the same regardless which user is calling your API, it can be shared and used in different requests.

Delegated permissions require a bit more effort to use. In this case you would need to exchange the access token your API received for a token to MS Graph API. But that token will be specific to that user, so they cannot be shared.

If you use application permissions, you can get the token using the scopes ["https://graph.microsoft.com/.default"] and your client id + secret/certificate.

With delegated permissions, you can use the same scopes. .default will use the permissions assigned to the app in the registration. But you will also have to include the access token that your API received.

One more issue that you can hit with delegated permissions is that if the user cannot access the data you are trying to access, it will fail. It's quite a nice property since you cannot get data the user cannot get.

There is no best option here. Application permissions are definitely easier. And if this app is only used in your organization and its okay from the administrators' side that your app can access any user's groups, then that might be what I'd go with.

But if permissions need to be limited, go with delegated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM