OAuth2.0 Practice (二)

上一篇文章中我们讲述了OAuth2.0的整体思路和运行流程, 以及其中一种授权方式: 授权码模式。在这篇文章中,我们将探索其余三种授权模式,并用我目前项目中的一部分作为Demo讲解。

简化模式

这个模式跳过了授权码这个步骤,客户端无需发送授权码给认证服务器。因此得名。

Simplify

步骤如下:

  1. 客户端将用户导向认证服务器。
  2. 用户决定是否给于客户端授权。
  3. 用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。这里的hash部分是指URL后面"#"后的值
  4. 浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值
  5. 资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
  6. 浏览器执行上一步获得的脚本,提取出令牌。
  7. 浏览器将令牌发给客户端。

第三步中,在服务器发回的HTTP Header中的location部分会包含hash部分,在hash中包含access token。这部分对所有访问者都可见。在开发iOS或Android App时,我们一搬用不到这种方式。过程极不安全,而且对于原生App来说,并不简便。

密码模式

在此模式中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

Password

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。当然还有另一种情况,就是认证服务器就是我们自己公司的服务器,既然客户端和服务器都是我们提供的服务,那么密码模式就要比授权模式更为简便。

步骤如下:

  1. 用户向客户端提供用户名和密码。
  2. 客户端将用户名和密码发给认证服务器,向后者请求令牌。
  3. 认证服务器确认无误后,向客户端提供访问令牌。

在发送请求时,"grant_type"类型一定要是"password"。并且整个过程客户端要做到不要保存用户密码。

客户端模式

严格来说,此模式不属于OAuth协议要解决的问题。用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。

Password

步骤如下:

  1. 客户端向认证服务器进行身份认证,并要求一个访问令牌。
  2. 认证服务器确认无误后,向客户端提供访问令牌。

在请求过程中,客户端需要把appid和appsecret发送给服务器即可。"grant_type"类型是"client_credential"

Demo

下面用我项目中的OAuth register和login来做一个小demo,包含一些代码片段。

首先,我们公司使用我们自己的服务器作为认证和资源服务器。

主要步骤:

  1. 客户端验证,看是不是使用我们的App进行登录或注册,用到客户端模式。
  2. OAuth Login, 使用密码模式登录,重新获取access token(与上一步的一样)和refresh token(上一步为nil)

代码片段如下:

- (void)preregistrationWithEmail:(NSString *)email
                    successBlock:(void(^)(id response))success
                 andFailureBlock:(void (^)(NSError *error))failure
{
 if (!self.token || self.token.tokenType.integerValue == TokenTypePassword) {
    [self requestClientCredentialsTokenWithSuccessBlock:^{
        [self preregistrationWithEmail:email successBlock:^(id response) {
            success(response);
        } andFailureBlock:^(NSError *error) {
            failure(error);
        }];
    } andFailureBlock:^(NSError *error) {
        failure(error);
    }];
} else {
    // check email request
    [self checkUserEmail:email withSuccessBlock:^(id response) {
        dispatch_async_in_main_queue(^{
            success(response);
        });
    } andFailureBlock:^(NSError *error) {
        dispatch_async_in_main_queue(^{
            failure(error);
        });
    }];
  }
}

这个函数其实是检测用户是否注册过我们的App,如果有,则再输入密码后进行OAuth Login步骤;若没有则输入用户名和密码后再进行OAuth Login。requestClientCredentialsTokenWithSuccessBlock 这个函数就是使用客户端模式授权的具体函数,如下:

- (void)requestClientCredentialsTokenWithSuccessBlock:(void(^)(void))success
                                      andFailureBlock:(void (^)(NSError *error))failure
{
     GFTRequestCompletionBlock requestBlock = ^(GFTBaseRequest * request){
       GFTCredentialsTokenRequest *credentialReq = (GFTCredentialsTokenRequest *)request;
    
       if (nil == request.error) {
          self.token = credentialReq.token;
        
          [[GFTRequestTaskManager sharedManager] updateCredential:self.token];
          success();
       } else {
          failure(request.error);
       }
     };

   GFTCredentialsTokenRequest *request = [[GFTCredentialsTokenRequest alloc] initWithCompletion:requestBlock];
   [request send];

}

其中用到的 GFTCredentialsTokenRequest 的HTTP Body如下:

- (NSDictionary *)reqBody
{
   NSMutableDictionary * reqBody = [NSMutableDictionary dictionary];

   reqBody[@"grant_type"]   = @"client_credentials";
   reqBody[@"client_id"]  = [GFTRequestTaskManager clientId];
   reqBody[@"client_secret"] = [GFTRequestTaskManager clientSecret];

   return reqBody;
}

大家可以看到,grant_type是"client_credentials"。

当检测完这些,就是验证用户登录了:

- (void)authenticateWithEmail:(NSString *)email
                     password:(NSString *)password
                 successBlock:(void(^)(id response))success
              andFailureBlock:(void (^)(NSError *error))failure
{
    GFTRequestCompletionBlock requestBlock = ^(GFTBaseRequest * request){
        GFTAuthenticationRequest *authRequest = (GFTAuthenticationRequest *)request;
    
        if (nil == authRequest.error) {
            self.token = authRequest.token;
            [[GFTRequestTaskManager sharedManager] updateCredential:self.token];
        
            dispatch_async_in_main_queue(^{
                success(@"success auth!");
            });
        } else {
            dispatch_async_in_main_queue(^{
                failure(request.error);
            });
        }
    };

    GFTAuthenticationRequest *authRequest = [[GFTAuthenticationRequest alloc] initWithCompletion:requestBlock];
    authRequest.userEmail = email;
    authRequest.userPassword = password;

    [authRequest send];
}

其中用到的 GFTAuthenticationRequest 的HTTP Body如下:

- (NSDictionary *)reqBody
{
    NSMutableDictionary * reqBody = [NSMutableDictionary dictionary];

    reqBody[@"username"]   = self.userEmail;
    reqBody[@"password"]   = self.userPassword;
    reqBody[@"grant_type"] = @"password";
    reqBody[@"scope"]      = @"user";
    reqBody[@"client_id"]  = [GFTRequestTaskManager clientId];
    reqBody[@"client_secret"] = [GFTRequestTaskManager clientSecret];

    return reqBody;
}

大家可以看到,grant_type是"password"。

以上就是OAuth2.0的一些简单应用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351

推荐阅读更多精彩内容

  • OAuth 是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版...
    badcyc阅读 264评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,642评论 18 139
  • 1. 微服务架构介绍 1.1 什么是微服务架构? 形像一点来说,微服务架构就像搭积木,每个微服务都是一个零件,并使...
    静修佛缘阅读 6,639评论 0 39
  • 就在刚才,接到班里孩子邓海宽妈妈打来的电话。她跟我说因为家里的一些问题,夫妻俩打算到外地去发展。可是,又担心...
    微笑着生活一一秀琴阅读 384评论 0 1
  • 当你去驾校学车,有一个这样的教练时,你一定不会犯困。因为你有一个好教练,不仅技术好人还幽默。这样的教练你怎么会舍得...
    火猫HK阅读 2,340评论 41 57