一般的社交提供商不提供一个Web Service进行身份验证(有很好的理由),而提供一个身份验证的界面,其中包含了某种协议如OpenID(连接)或使用OAuth2认证。这意味着客户端应用必须使用一个浏览器来展现这些UI部件---典型的登录页面和一些类型的许可界面。

这通常通过导航到一个众所周知的URL (网页API的模板使用OAuth2隐流程方法),并等待,直到在其他一些知名的URL会发生回调。在回调的访问令牌(加上一些元数据)通过散列片段连接。什么是之间发生的事情是总长达授权服务器,其与外部登录供应商的协调。客户端不需要知道该怎么做,这是很好的。

个人帐户帐户控制功能,查询已注册的中间件,并告诉和客户端的外部供应商提供哪些URL它必须使用来获得流量去的端点。这个信息可以被用来塑造客户端应用程序的用户界面:

private async Task GetExternalLoginsAsync()
{
var client = new HttpClient { BaseAddress = new Uri(_baseAddress) };
var response = await client.GetAsync(
“api/account/externalLogins?returnUrl=/&generateState=true”);
response.EnsureSuccessStatusCode(); _externalLogins = await response.Content.ReadAsAsync<
List<ExternalLoginViewModel>>();
}

外部登录模型如:

public class ExternalLoginViewModel
{
public string Name { get; set; }
public string Url { get; set; }
public string State { get; set; }
}

Url is the start URL (the callback URL is hardcoded to the base address in the template) and State is a random number that gets round tripped and should be checked on the callback (see the OAuth2 spec for details). The Url looks like this (sample):

/api/Account/ExternalLogin?
  provider=Google&
  response_type=token&
  client_id=self&
  redirect_uri=https://localhost/&
  state=as..aaa

The /api/account/externalLogin endpoint maps to the GetExternalLogin action on the account controller which has quite an interesting combination of attributes:

[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]

This basically means: don’t care about bearer tokens but allow anonymous access or an external cookie (see part 1).

In addition this endpoint also maps to the authorize endpoint of the OAuth2 authorization server middleware (check startup) which is kind of a black belt trick. First the middleware processes the request and then passes it on to whatever framework handles the URL – in this case Web API.

The exact course of events is quite involved. Let’s start with the moment when the web view hits the URL for the first time (check out the source code in parallel):

  1. Access /api/account/externalLogin?provider=Google…
    1. the user is not authenticated
    2. signal the middleware that is responsible for the requested external provider to do the protocol handshake (in this case Google)
  2. The user signs in at Google and does the consent
    1. Google calls back to the Web API using the /signin-google URL
  3. The Google middleware does its back channel communication and sets an external cookie containing some of the claims that came back from Google
    1. the middleware then redirects back to the /api/account/externalLogin endpoint
  4. This time the user is authenticated via the external cookie
    1. The account controller now checks if the login provider / user id combination is already registered in the local database
    2. this is not the case, so the account controller passes control back to the authorization server middleware instructing it to issue a token that contains the claims from Google (external bearer – the claims issuer is Google – again – check part one for the subtle meaning of that).
  5. The callback URL is invoked, and the client application retrieves the access token

At this point the client app has an access token, but it won’t get accepted by default since the claims are not issued by LOCAL AUTHORITY but Google instead. At this point you could open up endpoints by adding:

[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]

One endpoint that is configured exactly like that is the /api/account/registerExternal. This endpoints accepts the token you get from the previous step and allows it to associate with a new local account (without a password):

private void RegisterExternal_Click(object sender, RoutedEventArgs e)
{
var client = new HttpClient { BaseAddress = new Uri(_baseAddress) };
client.SetBearerToken(_externalResponse.AccessToken); var data = new Dictionary<string, string>
{
{ “UserName”, “dominick” }
}; var response = client.PostAsync(
“api/account/registerExternal”,
new FormUrlEncodedContent(data)).Result;
response.EnsureSuccessStatusCode();
}

RegisterExternal uses the ASP.Identity API to create a new user account and associates that with the external provider and user id from the token.

Now the last step is to go back to /api/account/externalLogin to get a new token that now represents a local account (or technically speaking claims from LOCAL AUTHORITY). The flow is like this:

  1. Invoke externalLogin with the same URL as before
    1. the user is still authenticated using the same external cookie
    2. the login provider / user id pair is now registered
  2. The controller clears the external cookie
    1. and creates a new authentication ticket
    2. this ticket translates to a new token with an issuer of LOCAL AUTHORITY – aka local account
  3. The callback URL transmits the token back to the client

Mission accomplished – the client used an external login provider to authenticate the user and linked that login to an account in its backend. Quite a stunt.

Web Api 2 用户认证模板解析-----外部用户认证模式的更多相关文章

  1. Web Api2 用户认证模板解析---本地用户

    本文我们将把关注Visual Studio用户认证模板中的 本地用户名/密码帐号特性.他们将其分为了两部分:帐户控制器具备如创建帐号和修改密码等功能:另一部分是在OAuth2认证服务器中进行的认证.我 ...

  2. ASP.NET Web API 安全验证之摘要(Digest)认证

    在基本认证的方式中,主要的安全问题来自于用户信息的明文传输,而在摘要认证中,主要通过一些手段避免了此问题,大大增加了安全性. 1.客户端匿名的方式请求 (无认证) HTTP/ Unauthorized ...

  3. ASP.NET Web API与Owin OAuth:调用与用户相关的Web API

    在前一篇博文中,我们通过以 OAuth 的 Client Credential Grant 授权方式(只验证调用客户端,不验证登录用户)拿到的 Access Token ,成功调用了与用户无关的 We ...

  4. ASP.NET Web API与Owin OAuth:调用与用户相关的Web API(非第三方登录)

    授权完成添加属性 ClaimsIdentity oAuthIdentity = await CreateAsync(user/*userManager*/, OAuthDefaults.Authent ...

  5. Asp.net MVC使用FormsAuthentication,MVC和WEB API可以共享身份认证 (转载)

    在实际的项目应用中,很多时候都需要保证数据的安全和可靠,如何来保证数据的安全呢?做法有很多,最常见的就是进行身份验证.验证通过,根据验证过的身份给与对应访问权限.同在Web Api中如何实现身份认证呢 ...

  6. ASP.NET Web API安全认证

    http://www.cnblogs.com/codeon/p/6123863.html http://open.taobao.com/docs/doc.htm?spm=a219a.7629140.0 ...

  7. 控制台程序(C#)不弹出认证窗口连接到Dynamics CRM Online的Web API

    摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复271或者20180602可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...

  8. Web API 2 入门——使用ASP.NET Web API和Angular.js构建单页应用程序(SPA)(谷歌翻译)

    在这篇文章中 概观 演习 概要 由网络营 下载网络营训练包 在传统的Web应用程序中,客户机(浏览器)通过请求页面启动与服务器的通信.然后,服务器处理请求,并将页面的HTML发送给客户端.在与页面的后 ...

  9. 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用

    由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...

随机推荐

  1. deque 居然已经实现了 insert 接口

    最近有个开发需求,根据server传递来的广告位来展示某条广告. 但最终存储广告的数据结构是deque,里面存储的东西还是对象(stl 基于拷贝语义). 想了半天,在开头和结尾插入比较方便,在中间插入 ...

  2. C#下载http文件

    @(编程) using System; using System.IO; using System.Net; namespace Wisdombud.Util { public class HttpH ...

  3. HDU 5777 domino (排序,水题)

    题意:小白在玩一个游戏.桌子上有n张多米诺骨牌排成一列.它有k次机会,每次可以选一个还没有倒的骨牌,向左或者向右推倒.每个骨 牌倒下的时候,若碰到了未倒下的 骨牌,可以把它推倒.小白现在可以随意设置骨 ...

  4. test是否被执行?

    procedure TForm2.Button1Click(Sender: TObject);  function test(value:boolean):boolean;  begin    res ...

  5. Lotus 迁移到Exchange POC 之 新建2007 服务器!

    我们登录到Exchange 2007 服务器,由于需要对AD进行扩展,我们首先必须完成架构扩展,由于默认没有ldifde工具,所以我们需要执行servermanagercmd –I rsat-adds ...

  6. [Mac]Mac中显示资源库文件夹

    在 Mac OS X 10.7 Lion 之后的版本中 , 用户的个人目录内的资源库文件默认是隐藏状态. 这个设定可能是为了避免用户误操作. 但是对于中高级用户来说会有些不变. 通过如下方式可以找回被 ...

  7. C#用正则表达式 获取标签的属性或值

    整理两个 在C#中,用正则表达式 获取网页源代码标签的属性或值的方法 : 1.获取标签中的值: string str="<a href=\"www.csdn.net\&quo ...

  8. 有关获取session属性时报nullPointException(空指针异常)的解决方案

    一般我们在从session中获取数据时,需要先进行赋值,也就是必须先进行session.setAttribute(String,Object)方法进行赋值,然后我们才能从session中获取内容,但是 ...

  9. props 和 state的区别

    作者:孙志勇 微博 日期:2016年11月29日 一.时效性 所有信息都具有时效性.文章的价值,往往跟时间有很大关联.特别是技术类文章,请注意本文创建时间,如果本文过于久远,请读者酌情考量,莫要浪费时 ...

  10. Netty4.x分析(转)

    官网定义: netty是一个异步.事件驱动的网络应用框架,用于快速开发可维护的.高性能的服务端和客户端程序. 原理分析 Architecture Overview 网络模型:netty采用了React ...