筆記下新增 Azure AD 帳號登入的相關資訊
2021-11-3
如果登入後收到以下錯誤訊息
Self-registration is disabled for this application
這邊需要確保 AD User 的 Mail 欄位有值
因為流程上會需要取得使用者信箱來做新增使用者或是關聯使用者
2021/9/28
.Net 5 微軟改用 MSAL 來處理 AAD 登入
重大變更:驗證: AzureAD UI 和 AzureADB2C。 UI Api 和標記為過時的封裝 - .NET | Microsoft Docs
MSAL 的 ABP 請參考
範例
PM> Install-Package Microsoft.Identity.Web
MyWebModule.cs (Web層)
context.Services.AddAuthentication()
// ...其他登入方式...
.AddMicrosoftIdentityWebApp(configuration);
context.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.GetClaimsFromUserInfoEndpoint = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});
appsetting.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "mydomain.onmicrosoft.com",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"CallbackPath": "/signin-azuread-oidc",
"ClientSecret": "set env variables or appsettings.secrets.json"
}
這樣就可以用AAD登入了,登入後會在 AbpUserLogins 新增如下資料,來對應至 UserId
如果要改 LoginPovider => AzureAdOpenId 可以用以下方式
.AddMicrosoftIdentityWebApp(configuration,openIdConnectScheme:"AzureAdOpenId");
context.Services.Configure<OpenIdConnectOptions>("AzureAdOpenId", options =>
主要可能會想要有多種外部登入 (GoogleOpenId,FbOpenId,AzureAdOpenId…ETC.) 的情境了話可以參考一下。
2021/9/9
自建AAD帳號必須要設定該User的Email,因為ABP會需要拿這個當作帳號來創建或關聯使用者,如果沒有則AAD登入後會導到註冊頁面。
2021/9/1
Azure App Service 存取限制 導致自己Get自己 403 | Jakeuj - 點部落 (dotblogs.com.tw)
2021/8/31
appsettings.secrets.json
appsettings.secrets.json 會複寫 Azure App Service 環境變數
因此如果要使用環境變數,則部署時 AzureAd.ClientSecret
不能出現在 appsettings.secrets.json
依照部署方式不同,處理方式可能不太一樣,使用 Git 做 CI/CD 可以保持 appsettings.secrets 為空並藉由忽略該檔案來達成
直接從 IDE build & publish 可能要自己清空 appsettings.secrets 或是直接不使用環境變數改由 appsettings.secrets 定義
唯使用 Git 時不可把 AzureAd.ClientSecret
寫在 appsettings.secrets 並 push 到 repo 造成資安疑慮
500 Server Error (IDX20803: Unable to obtain configuration from)
Identify Server 4 讀不到 configuration 就會報錯誤,原因可能有很多,但錯誤訊息可能都是這條,
因為詳細錯誤紀錄要另外設定 Services.AddAuthentication() 在這上面
加上以下程式碼可以顯示詳細錯誤訊息
IdentityModelEventSource.ShowPII = true;
如果打開後看到SSL錯誤,可能需要加上以下程式碼 (如果你使用 TLS 1.2)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
以上程式碼都是加在 Startup.cs > ConfigureServices 裡頭
我打開後則是看到 403,才想到我有設定 Azure App Service IP 限制自己 IP
雖然我整個網站都可以成功訪問,但看來內部取得該設定檔卻被擋住,難不成我要開 127.0.0.1 ?
總之打開錯誤訊息之後,就比較方便 Debug,省得繞一大圈
暫時先把 IP 限制拿掉,可以正常訪問 API,不再噴 500 了
結論
How to Setup Azure Active Directory and Integrate Abp Angular Application | ABP Community
WebModule.cs
.AddOpenIdConnect("AzureOpenId", "Azure AD OpenId", options =>
{
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
options.ClientId = configuration["AzureAd:ClientId"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.ClientSecret = configuration["AzureAd:ClientSecret"];
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});
appsettings.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<azureAd-tenant-id>",
"ClientId": "<azureAd-client-id>",
"Domain": "domain.onmicrosoft.com",
"CallbackPath": "/signin-azuread-oidc",
"ClientSecret": "<azureAd-client-secret>"
}
Azure
首先需要到 Azure > Azure Active Directory > 應用程式註冊 > 新增註冊
其中會需要設定 CallbackURI 需樣與開發/生產環境中的設定一致
例如開發時設定:https://localhost:44375/signin-azuread-oidc
其中 port 需與開發 run 的 port 一樣
而路徑則等等要把一樣的值設定到 appsettings 裡面
路徑 /signin-azuread-oidc 貌似沒甚麼特別意思
可以自訂喜歡的名稱保持 Azure 設定與 appsetting 一致即可
憑證及祕密 這好像 2.0 要拿 email 需要用到 ClientSecret 最後拿來當作 User 的帳號
ABP
參照:How To/Azure Active Directory Authentication MVC | Documentation Center | ABP.IO
目前我成功的是照以上這份文件
大概是使用 Microsoft.AspNetCore.Authentication.AzureAD.UI 這個套件安裝到 Web 層
然後提供相關 Azure AD 的設定值
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "xxxx.onmicrosoft.com",
"ClientId": "30fa3c26-xxxx-4342-8acc-9d3400c28ad5",
"TenantId": "da99111d-385d-xxxx-b8bf-c06f82284e39",
"CallbackPath": "/signin-azuread-oidc",
"ClientSecret": "define.from.appsettings.secrets.json"
}
其中 ClientSecret
需要 Azure > Azure Active Directory > 應用程式註冊 > 上面新增的應用 > 憑證及祕密 裡面去生成
並設定到 appsettings.secrets.json
如下所示
{
"AzureAd": {
"ClientSecret": "xx-xx.x_xxxxxxxxxx-xxxxx"
}
}
當然直接設到 appsettings.json 也不是不行,只是敏感資料建議獨立設定在 secrets,並且不 commit 到 git 裡面
最後在 WebModule 裡面註冊以下服務
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.Audience = "MyProjectName";
})
.AddAzureAD(options => configuration.Bind("AzureAd", options));
context.Services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.ClientId = configuration["AzureAd:ClientId"];
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.ValidateIssuer = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.Scope.Add("email");
});
}
其中 options.Audience = "MyProjectName";
裡面會是專案初始化時預先生成好的專案名稱
總之就是在原本 context.Services.AddAuthentication
的後面加上 .AddAzureAD
區段
是說用內建的 OpenId 也可以不用額外裝套件
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.Audience = "MyProjectName";
})
.AddOpenIdConnect("AzureOpenId", "Azure Active Directory OpenId", options =>
{
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
options.ClientId = configuration["AzureAd:ClientId"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
});
}
據我目前了解,這是比較通用於所有 OpenId 的方式,但反過來說相比專用於 Azure 的專用套件,他可能需要比較多的手動配置。
ま…我肉眼看到的差異目前只有以下這行
options.Authority = options.Authority + "/v2.0/";
上面是 AzureUI, 下面是 OpenId
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
asp.net 核心 - 微軟帳戶、AzureAD 和 OpenIdConnect 認證有何區別?- 堆疊溢出 (stackoverflow.com)
DEBUG
可以在最後加上一段 code, 然後下中斷點看拿了些甚麼東西(claims)回來
options.Scope.Add("email");
options.Events.OnTokenValidated = (async c =>
{
var claimsFromOidcProvider = c.Principal?.Claims.ToList();
await Task.CompletedTask;
});
其他 OpenID 登入
其他諸如 FB, Google, Microsoft….ETC. OpenID 登入請參照以下文檔進行設定
Modules/Account | Documentation Center | ABP.IO
services.AddAuthentication().AddTwitter(twitterOptions =>
{
twitterOptions.ConsumerKey = Configuration["Authentication:Twitter:ConsumerAPIKey"];
twitterOptions.ConsumerSecret = Configuration["Authentication:Twitter:ConsumerSecret"];
twitterOptions.RetrieveUserDetails = true;
});
最後大概長這樣
services.AddAuthentication()
.AddMicrosoftAccount(microsoftOptions => { ... })
.AddGoogle(googleOptions => { ... })
.AddTwitter(twitterOptions => { ... })
.AddFacebook(facebookOptions => { ... });
延伸閱讀
略過登入畫面,直接將使用者導向 Azure AD 帳號密碼登入畫面,請參照以下這篇文章
ABP.IO WEB應用程式框架 關閉本地帳號註冊與登入 | 御用 - 點部落 (dotblogs.com.tw)
LDAP Admin & C# .Net Core Identity Server 4 | 御用小本本 - 點部落 (dotblogs.com.tw)