前言
今儿跟大家聊聊有关使用Azure AD来保护http://asp.net core web api的话题,说起Azure AD不知道大家是否有所了解,它的简称是AAD,全称是Azure Active Directory,也就是Azure活动目录。它的作用是在Azure上提供云端的身份认证和资源访问服务,我们可以通过Azure生成应用程序,使用微软平台进行认证,获取令牌来访问受保护的API资源。
上面是对Azure AD最简单的介绍,如果您想了解更多,可能还需要去微软官方文档去一探究竟。
准备工作
创建API项目
首先我们先创建一个http://asp.net core web api项目,这里我觉得大家都会,就不细说了,这里我选用的framework版本是core 3.1。
然后我们安装一下swagger
Install-Package Swashbuckle.AspNetCore
这部分准备工作就做完了
注册API应用
下面就进入我们的重头戏,进入azure注册我们应用,这里需要注册两个:
一个是我们受保护的api资源,这里我起名为webapi。
再注册个客户端,这里我使用的是swagger,我们就给它起个名字叫swagger吧。
进入azure中,选择应用注册
如果您找不到应用注册,可以在上方搜索栏中搜索“应用注册”。
进入之后,点击新注册
我们输入名字,选择任何组织目录,最后点击注册。
建好后有我们需要记录好两个地方,一个就是应用程序客户端ID和目录(租户) ID,也就是我们后面要用到的ClientID和TenantID。
还有个比较重要的地方就是终结点,由于每个国家都有独立的Azure门户,所以每个国家的终结点都不太一样,您可以点击“终结点”进行查阅中国地区的终结点是什么。
这里最常用的就是
OAuth 2.0 授权终结点(v1):
https://login.chinacloudapi.cn/organizations/oauth2/authorize
OAuth 2.0 令牌终结点(v1):
https://login.chinacloudapi.cn/organizations/oauth2/token
当然这地方有点小问题,就是终结点的url中的organization不能直接使用,而是要根据业务不同进行相应的调整,这个我们后面会说。
接下来我们在webapi中随便暴露一个scope,以便于我们的api可以暴露出去供客户端调用。
我们点击公开API,然后点击添加范围,在右侧框中随便输入点内容。
至此,API应用就添加完成了,下一步我们开始注册swagger应用
注册swagger应用
注册swagger前面部分跟注册api应用相同,这里就不赘述,建好后是这样的
这里我们同样需要记录应用程序ID(ClientID)
下面我们设置重定向URI,用来设置应用的回调地址的。点击“添加重定向URI”,进入设置界面,
平台配置处,点击添加平台,选择web
重定向URI处填写swagger oauth2的重定向地址:https://xxx/swagger/oauth2-redirect.html
隐式授权处勾选“访问令牌”和“ID令牌”
设置好后,点击保存。
我们下面设置api权限,这时刚才在api应用中设置的scope就起作用了。
点击API权限,添加权限,在右侧栏中选择我的API
点击刚才注册api应用,即Webapi
勾选好刚才创建的scope后,点击添加权限
这时我们swagger应用就有访问webapi的权限了
接下来还剩最后一步,就是生成客户端的secret。
点击证书和密码,点击新客户端密码,输入名称选择有效期
点击添加后会显示secret,此处一定要保存好,只有这一次机会,之后就再也看不到了,只能删了重新建一个了
至此,我们两个应用都注册完成了,下面我们回到刚才建好的api项目中,进行简单的配置。
web api配置
配置AAD信息
我们在appsettings中进行如下配置。
"AzureAd": {
"Instance": "https://login.chinacloudapi.cn/",
"ClientId": "d6fb563e-a81f-4467-b2a9-6a8bc81b3fd2",
"Domain": "bcrdc.partner.onmschina.cn",
"TenantId": "e080385b-9f8c-40ac-baad-0bf941f2a6a7"
},
"Swagger": {
"ClientId": "8e713d16-de8f-4fcc-b6fb-ca0636c2c019",
"Secret": "",
},
我简单说明一下
在AzureAd部分
Instance填入https://login.chinacloudapi.cn
ClientId和TenantId分别填入Webapi应用注册时的客户端ID和目录租户ID
Domain填入目录的domain,如果不知道去哪看,可以按下图查看当前domain
swagger部分
配置注册swagger应用时的应用程序ID和secret即可
服务注册
我们进入Startup.cs文件中进行相应的认证服务和swagger的注册,关键代码如下
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "AAD 认证和授权",
Type = SecuritySchemeType.OAuth2,
In = ParameterLocation.Header,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow
{
Scopes = new Dictionary<string, string>
{
{ "User.Read", "Access API" }
},
AuthorizationUrl = new Uri($"https://login.chinacloudapi.cn/{Configuration["AzureAd:TenantId"]}/oauth2/authorize")
}
}
});
// 在header中添加token,传递到后台
c.OperationFilter<SecurityRequirementsOperationFilter>();
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", $"AAD Web api demo v1");
c.OAuthClientId(Configuration["Swagger:ClientId"]);
c.OAuthClientSecret(Configuration["Swagger:Secret"]);
c.OAuthRealm(Configuration["AzureAd:ClientId"]);
c.OAuthAppName("My API V1");
c.OAuthScopeSeparator(" ");
c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>
{ { "resource", Configuration["AzureAd:ClientId"]} });
});
app.UseRouting();
app.UseAuthentication();//<---use authentication middleware
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
这里的代码不难理解,我主要说几点需要注意的,
{"User.Read","Access API"},这里User.Read是我们在webapi添加的公开api的scope的名称,后面access api是它的简短描述,这里会出现在认证窗口需要您勾选的左下角,一会您就会看到。
AuthorizationUrl,此处配置认证的终结点,还记得我刚才提过的,认证终结点url中的organizations需要调整嘛,这里我们将它替换为TenantId,这样就相当于单租户认证授权了。
接下来我们创建一个controller,并配置上 [Authorize],再随便写个action,用于测试
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
[HttpGet("{id}")]
public User Get(int id)
{
return new User{Id = id,Email=User?.Identity?.Name};
}
}
ok,至此,我们所有准备工作都做好了,跑起来试试
先不认证,直接调用试试,不出所料,直接401错误。
下面我们试试认证一下
此处client id自动填入swagger的client id是应为这个client id在UseSwaggerUI中配置了OAuthClientId,scopes就是我刚才提的配置scope的展示,我们点击Authorize,会跳到微软登录页面
登录完成后,会跳回到swagger中
这回我们再试试调用一次api,可以看到已经在头部自动带入bearer token了,请求也能正确返回了, 成功!
最后
今儿给大家简单介绍了Azure AD,并带大家配置2个应用注册,一个服务端一个客户端,并展示如何使用AAD保护我们的api资源,以及如何将swagger和AAD结合到一起使用。
目前实现的是单租户的用户登录,如果您登陆的账户隶属于别的租户下,那么肯定是不能通过的,下一步我将抽时间为大家介绍如何实现多租户的用户登录,回头见,bye~ ️ ️ ️