通常我們?cè)陂_發(fā)一個(gè)應(yīng)用時(shí),需要考慮用戶身份認(rèn)證及授權(quán),Office 365使用AAD(Azure Active Directory)作為其認(rèn)證機(jī)構(gòu),為應(yīng)用程序提供身份認(rèn)證及授權(quán)服務(wù)。因此,在開發(fā)Office 365應(yīng)用前,我們需要了解AAD的認(rèn)證和授權(quán)機(jī)制。
AAD認(rèn)證授權(quán)機(jī)制當(dāng)前的AAD支持多種身份認(rèn)證標(biāo)準(zhǔn): - OpenId Connect
- OAuth2
- SAML-P
- WS-Federation and WS-Trust
- Graph web api
這幾種身份認(rèn)證標(biāo)準(zhǔn)會(huì)應(yīng)用在不同的場(chǎng)景中,如OAuth2.0應(yīng)用于Office 365應(yīng)用程序接口,SAML-P多應(yīng)用于Office 365的混合部署,我們?cè)陂_發(fā)應(yīng)用的過(guò)程中,最主要是使用OpenID Connect和OAuth2.0.因此,本篇內(nèi)容中只涉及到OpenID和OAuth2.0兩種類型的身份認(rèn)證分析,后續(xù)文章中會(huì)涉及到Office 365的混合部署及令牌交換協(xié)議內(nèi)容。
OAuth2.0是OAuth的最新版本,升級(jí)并簡(jiǎn)化了驗(yàn)證的過(guò)程,在資源授權(quán)方面,OAuth2.0支持多種授予流,Office 365使用授權(quán)代碼授予流和客戶端憑證授予流,兩者適用于不同的應(yīng)用場(chǎng)景,同時(shí)在AAD中配置權(quán)限也進(jìn)行了區(qū)分,稍后會(huì)具體講解。下圖為標(biāo)準(zhǔn)的OAuth2.0處理過(guò)程:
OpenID是目前各大網(wǎng)站普遍支持的開放協(xié)議,OpenID Connect 1.0是基于OAuth2.0設(shè)計(jì)的用戶認(rèn)證標(biāo)準(zhǔn),Azure Active Directory (Azure AD) 中的 OpenID Connect 1.0 允許你使用 OAuth 2.0 協(xié)議進(jìn)行單一登錄。 OAuth 2.0 是一種授權(quán)協(xié)議,但 OpenID Connect 擴(kuò)展了 OAuth 2.0 的身份驗(yàn)證協(xié)議用途。OpenID Connect 協(xié)議(OpenId Connect 1.0)的主要功能是返回 id_token,后者用于對(duì)用戶進(jìn)行身份驗(yàn)證。<span id="mt4" class="sentence SentenceHover" data-guid="42ff71279f609ce44c6a4d52e2f52f5e" data-source=" For more information about OpenID Connect, see the specification, OpenID Connect Core 1.0." style="box-sizing: inherit;"> 下圖為OpenID的標(biāo)準(zhǔn)處理過(guò)程: OpenID的標(biāo)準(zhǔn)過(guò)程需要以下幾步: 1. 客戶端(RP)發(fā)送一個(gè)請(qǐng)求到OpenID的提供商(OP); 2. OP驗(yàn)證用戶,如果用戶尚未授權(quán),則跳轉(zhuǎn)到授權(quán)頁(yè)面; 3. 用戶授權(quán)后,OP會(huì)引導(dǎo)用戶返回到客戶端,并會(huì)攜帶一個(gè)Token和id token; 4. RP使用收到的Token請(qǐng)求用戶其他信息資源; 5. OP返回請(qǐng)求的資源信息
通過(guò)上述的步驟,第三方應(yīng)用(也就是客戶端)不僅可以驗(yàn)證用戶的合法性,同時(shí)可以在用戶授權(quán)的情況下獲取用戶基本信息。在AAD中使用的OpenID Connect 1.0為Auth2.0進(jìn)行了擴(kuò)展,在返回Token的同時(shí),會(huì)返回一個(gè)JWT形式的id_token。AAD中的OpenID終結(jié)點(diǎn)配置信息可通過(guò)訪問(wèn)此鏈接查看: https://login.windows.net/common/.well-known/openid-configuration 。id_token包含用戶的基本信息,作為應(yīng)用的CurrentUser屬性。獲取到Token后,應(yīng)用可以通過(guò)此憑證請(qǐng)求資源,Office 365使用Bearer方式獲取資源,請(qǐng)參閱Bearer Token Usage
授權(quán)代碼流和客戶端憑證授予流AAD中的授權(quán)代碼授予流使用如下流程: ![]() (此圖引用自msdn)
對(duì)比OAuth2.0的標(biāo)準(zhǔn)流程,授權(quán)代碼流會(huì)以授權(quán)代碼(Code)的方式返回授權(quán)標(biāo)識(shí),用戶通過(guò)使用Code請(qǐng)求資源Token,應(yīng)用程序使用獲取到的Token調(diào)用資源Web API。 當(dāng)我們的Office 365應(yīng)用使用授權(quán)代碼授予流時(shí),需要我們?cè)贏AD中設(shè)置資源代理權(quán)限,設(shè)置過(guò)程如下: (一)通過(guò)Office 365設(shè)置頁(yè)面進(jìn)入Azure AD:
(二)進(jìn)入AD中的應(yīng)用程序,并找到我們的注冊(cè)應(yīng)用(如何注冊(cè)應(yīng)用請(qǐng)參考),進(jìn)入應(yīng)用的Configure頁(yè)面,如下圖:
(三)設(shè)置資源的Delegated Permissions,如果我們使用過(guò)授權(quán)代碼流來(lái)請(qǐng)求資源,只需設(shè)置Delegation Permissions
AAD中的客戶端憑證授予流使用如下流程: ![]() (此圖引用自msdn) 與標(biāo)準(zhǔn)OAuth2.0流程相比,客戶端憑證授予流不需要用戶授權(quán),而是由應(yīng)用程序直接訪問(wèn)AAD請(qǐng)求token。請(qǐng)注意,如果使用此方式,則應(yīng)用程序?qū)Y源有最大權(quán)限。 當(dāng)我們的Office 365應(yīng)用使用授權(quán)代碼授予流時(shí),需要我們?cè)贏AD中設(shè)置資源的應(yīng)用權(quán)限,與授權(quán)代碼授予流只是配置權(quán)限不同,設(shè)置的是Application Permission,如下圖:
應(yīng)用示例在實(shí)際應(yīng)用中,我們通常會(huì)使用Owin中間件來(lái)完成用戶身份認(rèn)證,我們使用Office Dev Center中的實(shí)例來(lái)分析。 先來(lái)看如何實(shí)現(xiàn)用戶登錄后驗(yàn)證,我們貼出重要代碼來(lái)分析: - public partial class Startup
- {
- public void ConfigureAuth(IAppBuilder app)
- {
- app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
- app.UseCookieAuthentication(new CookieAuthenticationOptions());
- app.UseOpenIdConnectAuthentication(
- new OpenIdConnectAuthenticationOptions
- {
- ClientId = SettingsHelper.ClientId,
- Authority = SettingsHelper.Authority,
- TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
- {
- ValidateIssuer = false
- },
- Notifications = new OpenIdConnectAuthenticationNotifications()
- {
- AuthorizationCodeReceived = (context) =>
- {
- var code = context.Code;
- ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey);
- string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
- String signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
- AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}/{1}", SettingsHelper.AuthorizationUri, tenantID), new ADALTokenCache(signInUserId));
- AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);
- return Task.FromResult(0);
- },
- RedirectToIdentityProvider = (context) =>
- {
- string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
- context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
- context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
- return Task.FromResult(0);
- },
- AuthenticationFailed = (context) =>
- {
- context.HandleResponse();
- return Task.FromResult(0);
- }
- }
- });
- }
復(fù)制代碼
上述代碼在項(xiàng)目中的App_Start文件夾下Startup.Auth.cs,是Owin的Server端配置內(nèi)容。Owin中間件是在應(yīng)用啟動(dòng)時(shí)注冊(cè),注冊(cè)方式是掃描跟文件夾下的Startup.cs,存在則使用該配置類注冊(cè)。針對(duì)OWIN的處理機(jī)制,我們?cè)诤罄m(xù)的章節(jié)中單獨(dú)分析OWIN中間件的架構(gòu),當(dāng)前我們主要聚焦在如何使用OpenID及OAuth。在上面的代碼中,有這么一句: app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app是Owin中的基礎(chǔ)接口類型,用于內(nèi)部拓展不同的驗(yàn)證機(jī)制,使用IDictionary<string, object> Properties { get; }這樣一個(gè)字典類型存儲(chǔ)我們應(yīng)用程序驗(yàn)證所需的信息。SetDefaultSignInAsAuthenticationType指明Owin默認(rèn)使用的驗(yàn)證方式,為了保持用戶的登錄狀態(tài),我們使用cookie作為默認(rèn)驗(yàn)證方式,當(dāng)cookie未登錄時(shí),Owin繼續(xù)使用下面注冊(cè)的其他方式嘗試驗(yàn)證。
app.UseCookieAuthentication(new CookieAuthenticationOptions());
UseCookieAuthentication是Owin實(shí)現(xiàn)的Cookie驗(yàn)證方式。在Owin的源代碼中,每一種方式都包含基本的處理類:
- AuthenticationDefaults.cs
- AuthenticationExtensions.cs
- AuthenticationHandler.cs
- AuthenticationMiddleware.cs
- AuthenticationOptions.cs
此時(shí)我們使用new CookieAuthenticationOptions()初始化Cookie驗(yàn)證默認(rèn)配置。當(dāng)Cookie中無(wú)驗(yàn)證信息時(shí),會(huì)進(jìn)入到app.UseOpenIdConnectAuthentication
在OpenID驗(yàn)證中,配置了如下參數(shù):
- ClientId:應(yīng)用程序ID,標(biāo)識(shí)我們?cè)贏AD中的應(yīng)用
- Authority:發(fā)起驗(yàn)證請(qǐng)求的目標(biāo)地址,如當(dāng)前的https://login.windows.net,這里要說(shuō)明一下,根據(jù)我的實(shí)測(cè),https://login.microsoftonline.com也是可以的。
- TokenValidationParameters:這個(gè)方法是為了驗(yàn)證通過(guò)OpenID驗(yàn)證的用戶是否為本應(yīng)用程序的合法用戶,可根據(jù)業(yè)務(wù)實(shí)際情況編寫自己的驗(yàn)證機(jī)制。
- Notifications:在OpenID驗(yàn)證并返回后,Owin調(diào)用Notifications方法,也正是我們使用OAuth進(jìn)行用戶授權(quán)的觸發(fā)方法。
下面是一個(gè)TokenValidationParameters參數(shù)的示例: - TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
- {
- IssuerValidator = (issuer, token) =>
- {
- return DoesIssuerBelongToMyCustomersList(issuer);//DoesIssuerBelongToMyCustomersList方法根據(jù)當(dāng)前登陸人信息判斷是否在用戶列表中,如果不存在,則返回false
- }
- }
復(fù)制代碼
|