[ Office 365 开发系列 ] 身份认证
2016-04-29 13:44
351 查看
前言
本文完全原创,转载请说明出处,希望对大家有用。通常我们在开发一个应用时,需要考虑用户身份认证及授权,Office 365使用AAD(Azure Active Directory)作为其认证机构,为应用程序提供身份认证及授权服务。因此,在开发Office 365应用前,我们需要了解AAD的认证和授权机制。
阅读目录
AAD认证授权机制授权代码授予流和客户端凭证授予流
应用示例
正文
AAD认证授权机制
当前的AAD支持多种身份认证标准:OpenId Connect
OAuth2
SAML-P
WS-Federation and WS-Trust
Graph web api
这几种身份认证标准会应用在不同的场景中,如OAuth2.0应用于Office 365应用程序接口,SAML-P多应用于Office 365的混合部署,如果想要详细了解,可以参阅此文章,详细介绍了Office 365身份认证支持的各项协议。我们在开发应用的过程中,最主要是使用OpenID Connect和OAuth2.0.因此,本篇内容中只涉及到OpenID和OAuth2.0两种类型的身份认证分析,后续文章中会涉及到Office 365的混合部署及令牌交换协议内容。
OAuth2.0是OAuth的最新版本,升级并简化了验证的过程,相关描述可以查看RFC 6749,在资源授权方面,OAuth2.0支持多种授予流,Office 365使用授权代码授予流和客户端凭证授予流,两者适用于不同的应用场景,同时在AAD中配置权限也进行了区分,稍后会具体讲解。下图为标准的OAuth2.0处理过程:
+--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+
OpenID是目前各大网站普遍支持的开放协议,OpenID Connect 1.0是基于OAuth2.0设计的用户认证标准,Azure Active Directory (Azure AD) 中的 OpenID Connect 1.0 允许你使用 OAuth 2.0 协议进行单一登录。 OAuth 2.0 是一种授权协议,但 OpenID Connect 扩展了 OAuth 2.0 的身份验证协议用途。OpenID Connect 协议(OpenId Connect 1.0)的主要功能是返回 id_token,后者用于对用户进行身份验证。 下图为OpenID的标准处理过程:
+--------+ +--------+ | | | | | |---------(1) AuthN Request-------->| | | | | | | | +--------+ | | | | | | | | | | | End- |<--(2) AuthN & AuthZ-->| | | | | User | | | | RP | | | | OP | | | +--------+ | | | | | | | |<--------(3) AuthN Response--------| | | | | | | |---------(4) UserInfo Request----->| | | | | | | |<--------(5) UserInfo Response-----| | | | | | +--------+ +--------+
OpenID的标准过程需要以下几步:
1. 客户端(RP)发送一个请求到OpenID的提供商(OP);
2. OP验证用户,如果用户尚未授权,则跳转到授权页面;
3. 用户授权后,OP会引导用户返回到客户端,并会携带一个Token和id token;
4. RP使用收到的Token请求用户其他信息资源;
5. OP返回请求的资源信息
通过上述的步骤,第三方应用(也就是客户端)不仅可以验证用户的合法性,同时可以在用户授权的情况下获取用户基本信息。在AAD中使用的OpenID Connect 1.0为Auth2.0进行了扩展,在返回Token的同时,会返回一个JWT形式的id_token。AAD中的OpenID终结点配置信息可通过访问此链接查看:https://login.windows.net/common/.well-known/openid-configuration 。id_token包含用户的基本信息,作为应用的CurrentUser属性。获取到Token后,应用可以通过此凭证请求资源,Office 365使用Bearer方式获取资源,请参阅Bearer Token Usage
授权代码流和客户端凭证授予流
AAD中的授权代码授予流使用如下流程:public class ADALTokenCache : TokenCache { string User; UserTokenCache Cache; // constructor public ADALTokenCache(string user) { // associate the cache to the current user of the web app User = user; this.AfterAccess = AfterAccessNotification; this.BeforeAccess = BeforeAccessNotification; this.BeforeWrite = BeforeWriteNotification; using (ApplicationDbContext db = new ApplicationDbContext()) { Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User); } this.Deserialize((Cache == null) ? null : Cache.cacheBits); } public override void Clear() { base.Clear(); using (ApplicationDbContext db = new ApplicationDbContext()) { Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User); if (Cache != null) db.UserTokenCacheList.Remove(Cache); db.SaveChanges(); } } void BeforeAccessNotification(TokenCacheNotificationArgs args) { using (ApplicationDbContext db = new ApplicationDbContext()) { if (Cache == null) { // first time access Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User); } else { // retrieve last write from the DB var status = from e in db.UserTokenCacheList where (e.webUserUniqueId == User) select new { LastWrite = e.LastWrite }; // if the in-memory copy is older than the persistent copy if (status != null && status.Count() > 0 && status.First().LastWrite > Cache.LastWrite) { Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User); } } } this.Deserialize((Cache == null) ? null : Cache.cacheBits); } // Notification raised after ADAL accessed the cache. // If the HasStateChanged flag is set, ADAL changed the content of the cache void AfterAccessNotification(TokenCacheNotificationArgs args) { if (this.HasStateChanged) { using (ApplicationDbContext db = new ApplicationDbContext()) { if (Cache == null || Cache.UserTokenCacheId == 0) { Cache = new UserTokenCache { webUserUniqueId = User, cacheBits = this.Serialize(), LastWrite = DateTime.Now }; } else { Cache.cacheBits = this.Serialize(); Cache.LastWrite = DateTime.Now; } db.Entry(Cache).State = Cache.UserTokenCacheId == 0 ? EntityState.Added : EntityState.Modified; db.SaveChanges(); } this.HasStateChanged = false; } } void BeforeWriteNotification(TokenCacheNotificationArgs args) { // if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry } }
View Code
这里我修改了一些代码,示例中的代码是用户每次获取新资源的Token时新增一条Cache数据,为了多用户访问,我将缓存机制改为每个用户对应一条Cache数据。
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);
AcquireTokenByAuthorizationCode是ADAL帮我们定义好的授权代码流方法,用于通过code获取token,同时我们指定请求SettingsHelper.AADGraphResourceId(AAD Graph web resource)资源,这样可以验证我们的应用是否有对应资源的访问权限。当然,这个参数是可选的。
验证逻辑图如下:
结束语
Office 365开发系列的身份认证就到这里了,如有不明白的地方,请在评论中提出。后续章节我们会继续深入了解OWIN及ADAL的机制,希望大家继续关注。相关文章推荐
- jQuery函数的等价原生函数【转载】
- Guava教程-RateLimiter
- MongoDB 针对嵌套对象,多层级结构存储,增删改查
- 学习scanf的一些摘录
- 博客转移到github上了,csdn的博客就关了。
- Excel函数
- HDU 1001 Sum Problem
- 33层高楼为什么27楼和28楼最贵 次顶层房价高原因揭秘
- novnc的替代品Guacamole
- 心灵鸡汤之20160429
- swift 扫描二维码/条形码,开启闪光灯,识别相册二维码
- IOS IAP APP内支付 Java服务端代码
- 数据结构之字符串ADT
- HDU 1000 A + B Problem
- Error:Execution failed for task ':app:transformClassesWithDexForDebug&#
- Git基础学习记录(一)
- Android 监听前台后台切换
- 200多种Android动画效果的强悍框架,总有你想要的
- Android 编程下 Touch 事件的分发和消费机制
- iOS国际化时遇到的异常:read failed: the data couldn't be read because it isn't in the correct format