本文转自:http://andrewlock.net/an-introduction-to-oauth-2-using-facebook-in-asp-net-core/

This is the next post in a series on authentication and authorisation in ASP.NET Core. In this post I look in moderate depth at the OAuth 2.0 protocol as it pertains to ASP.NET Core applications, walking through the protocol as seen by the user of your website as well as the application itself. Finally, I show how you can configure your application to use a Facebook social login when you are using ASP.NET Core Identity.

OAuth 2.0

OAuth 2.0 is an open standard for authorisation. It is commonly used as a way for users to login to a particular website (say, catpics.com) using a third party account such as a Facebook or Google account, without having to provide catpics.com the password for their Facebook account.

While it is often used for authentication, being used to log a user in to a site, it is actually an authorisationprotocol. We'll discuss the detail of the flow of requests in the next sections, but in essence, you as a user are providing permission for the catpics.com website to access some sort of personal information from the OAuth provider website (Facebook). So catpics.com is able to access your personal Facebook cat pictures, without having full access to your account, and without requiring you to provide your password directly.

There are a number of different ways you can use OAuth 2.0, each of which require different parameters and different user interactions. Which one you should use depends on the nature of the application you are developing, for example:

  • Resource Owner Grant - Requires the user to directly enter their username and password to the application. Useful when you are developing a 1st party application to authenticate with your own servers, e.g. the Facebook mobile app might use a Resource Owner Grant to authenticate with Facebook's servers.
  • Implicit Grant - Authenticating with a server returns an access token to the browser which can then be used to access resources. Useful for Single Page Applications (SPA) where communication cannot be private.
  • Authorisation Code Grant - The typical OAuth grant used by web applications, such as you would use in your ASP.NET apps. This is the flow I will focus on for the rest of the article.

The Authorisation Code Grant

Before explaining the flow fully, we need to clarify some of the terminology. This is where I often see people getting confused with the use of overloaded terms like 'Client'. Unfortunately, these are taken from the official spec, so I will use them here as well, but for the remainder of the article I'll try and use disambiguated names instead.

We will consider an ASP.NET application that finds cats in your Facebook photos by using Facebook's OAuth authorisation.

  • Resource owner (e.g. the user) - This technically doesn't need to be a person as OAuth allows machine-to-machine authorisation, but for our purposes it is the end-user who is using your application.
  • Resource service (e.g. the Facebook API server) - This is the endpoint your ASP.NET application will call to access Facebook photos once it has been given an access token.
  • Client (e.g. your app) - This is the application which is actually making the requests to the Resource service. So in this case it is the ASP.NET application.
  • Authorisation server (e.g. the Facebook authorisation server) - This is the server that allows the user to login to their Facebook account.
  • Browser (e.g. Chrome, Safari) - Not required by OAuth in general, but for our example, the browser is the user-agent that the resource owner/user is using to navigate your ASP.NET application.

The flow

Now we have nailed some of the terminology, we can think about the actual flow of events and data when OAuth 2.0 is in use. The image below gives a detailed overview of the various interactions, from the user first requesting access to a protected resource, to them finally gaining access to it. The flow looks complicated, but the key points to notice are the three calls to Facebook's servers.

As we go through the flow, we'll illustrate it from a user's point of view, using the default MVC template with ASP.NET Core Identity, configured to use Facebook as an external authentication mechanism.

Before you can use OAuth in your application, you first need to register your application with the Authorisation server (Facebook). There you will need to provide a REDIRECT_URI and you will be provided a CLIENT_ID and CLIENT_SECRET. The process is different for each Authorisation server so it is best to consult their developer docs for how to go about this. I'll cover how to register your application with Facebook later in this article.

Authorising to obtain an authorisation code

When the user requests a page on your app that requires authorisation, they will be redirected to the login page. Here they can either login using a username and password to create an account directly with the site, or they can choose to login with an external provider - in this case just Facebook.

When the user clicks on the Facebook button, the ASP.NET application sends a 302 to the user's browser, with a url similar to the following:

https://www.facebook.com/v2.6/dialog/oauth?client_id=CLIENT_ID&scope=public_profile,email&response_type=code&redirect_uri=REDIRECT_URI&state=STATE_TOKEN

This url points to the Facebook Authorisation server, and contains a number of replacement fields. TheCLIENT_ID and REDIRECT_URI are the ones we registered and were provided when we registered our app in Facebook. The STATE_TOKEN is a CSRF token generated automatically by our application for security reasons (that I won't go into). Finally, the scope field indicates what resources we have requested access to - namely public_profile and their email.

Following this link, the user is directed in their browser to their Facebook login page. Once they have logged in, or if they are already logged in, they must grant authorisation to our registered ASP.NET application to access the requested fields:

If the user clicks OK, then Facebook sends another 302 response to the browser, with a url similar to the following:

http://localhost:5000/signin-facebook?code=AUTH_CODE&state=STATE_TOKEN

Facebook has provided an AUTH_CODE, along with the STATE_TOKEN we supplied with the initial redirect. The state can be verified to ensure that requests are not being forged by comparing it to the version stored in our session state in the ASP.NET application. The AUTH_CODE however is only temporary, and cannot be directly used to access the user details we need. Instead, we need to exchange it for an access token with the Facebook Authorisation server.

Exchanging for an access token

This next portion of the flow occurs entirely server side - communication occurs directly between our ASP.NET application and the Facebook authorisation server.

Our ASP.NET application constructs a POST request to the Facebook Authorization server, to an Access token endpoint. The request sends our app's registered details, including the CLIENT_SECRET and theAUTH_TOKEN to the Facebook endpoint:

POST /v2.6/oauth/access_token HTTP/1.1
Host: graph.facebook.com
Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET

If the token is accepted by Facebook's Authorisation server, then it will respond with (among other things) an ACCESS_TOKEN. This access token allows our ASP.NET application to access the resources (scopes) we requested at the beginning of the flow, but we don't actually have the details we need in order to create the Claims for our user yet.

Accessing the protected resource

After receiving and storing the access token, our app can now contact Facebook's Resource server. We are still completely server-side at this point, communicating directly with Facebook's user information endpoint.

Our application constructs a GET request, providing the ACCESS_TOKEN and a comma separated (and URL encoded) list of requested fields in the querystring:

GET /v2.6/me?access_token=ACCESS_TOKEN&fields=name%2Cemail%2Cfirst_name%2Clast_name
Host: graph.facebook.com

Assuming all is good, Facebook's resource server should respond with the requested fields. Your application can then add the appropriate Claims to the ClaimsIdentity and your user is authenticated!

The description provided here omits a number of things such as handling expiration and refresh tokens, as well as the ASP.NET Core Identity process or associating the login to an email, but hopefully it provides an intermediate view of what is happening as part of a social login.

Example usage in ASP.NET Core

If you're anything like me, when you first start looking at how to implement OAuth in your application, it all seems a bit daunting. There's so many moving parts, different grants and backchannel communication that it seems like it will be a chore to setup.

Luckily, the ASP.NET Core team have solved a massive amount of the headache for you! If you are using ASP.NET Core Identity, then adding external providers is a breeze. The ASP.NET Core documentationprovides a great walkthrough to creating your application and getting it all setup.

Essentially, if you have an app that uses ASP.NET Core Identity, all that is required to add facebook authentication is to install the package in your project.json:

{
"dependencies": {
"Microsoft.AspNetCore.Authentication.Facebook": "1.0.0"
}
}

and configure the middleware in your Startup.Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ app.UseStaticFiles(); app.UseIdentity(); app.UseFacebookAuthentication(new FacebookOptions
{
AppId = Configuration["facebook:appid"],
AppSecret = Configuration["facebook:appsecret"],
Scope = { "email" },
Fields = { "name", "email" },
SaveTokens = true,
}); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}

You can see we are loading the AppId and AppSecret (our CLIENT_ID and CLIENT_SECRET) from configuration. On a development machine, these should be stored using the user secrets manager or environment variables (never commit them directly to your repository).

If you want to use a different external OAuth provider then you have several options. Microsoft provide a number of packages similar to the Facebook package shown which make integrating external logins simple. There are currently providers for Google, Twitter and (obviously) Microsoft accounts.

In addition, there are a number of open source libraries that provide similar handling of common providers. In particular, the AspNet.Security.OAuth.Providers repository has middleware for providers like GitHub, Foursquare, Dropbox and many others.

Alternatively, if a direct provider is not available, you can use the genericMicrosoft.AspNetCore.Authentication.OAuth package on which these all build. For example Jerrie Pelser has an excellent post on configuring your ASP.NET Core application to use LinkedIn.

Registering your application with Facebook Graph API

As discussed previously, before you can use an OAuth provider, you must register your application with the provider to obtain the CLIENT_ID and CLIENT_SECRET, and to register your REDIRECT_URI. I will briefly show how to go about doing this for Facebook.

First, navigate to https://developers.facebook.com and login. If you have not already registered as a developer, you will need to register and agree to Facebook's policies.

Once a developer, you can create a new web application by following the prompts or navigating tohttps://developers.facebook.com/quickstarts/?platform=web. Here you will be prompted to provide a name for your web application, and then to configure some basic details about it.

Once created, navigate to https://developers.facebook.com/apps and click on your application's icon. You will be taken to your app's basic details. Here you can obtain the App Id and App Secret you will need in your application. Make a note of them (store them using your secrets manager).

The last step is to configure the redirect URI for your application. Click on '+ Add Product' at the bottom of the menu and choose Facebook Login. This will enable OAuth for your application, and allow you to set the REDIRECT_URI for your application.

The redirect path for the Facebook middleware is /signin-facebook. In my case, I was only running the app locally, so my full redirect url was http://localhost:5000/signin-facebook.

Assuming everything is setup correctly, you should now be able to use OAuth 2.0 to login to your ASP.NET Core application with Facebook!

Final thoughts

In this post I showed how you could use OAuth 2.0 to allow users to login to your ASP.NET Core application with Facebook and other OAuth 2.0 providers.

One point which is often overlooked is the fact that OAuth 2.0 is a protocol for performing authorisation, not authentication. The whole process is aimed at providing access to protected resources, rather than proving the identity of a user, which has some subtle security implications.

Luckily there is an another protocol OpenId Connect, which deals with many of these issues, which essentially provides and additional layer on top of the OAuth 2.0 protocol. I'll be doing a post on OpenId Connect soon, but if you want to learn more, I've provided some additional details below.

In the mean time, enjoy your social logins!

Further links

[转]An introduction to OAuth 2.0 using Facebook in ASP.NET Core的更多相关文章

  1. Asp.net Core 1.0.1升级到Asp.net Core 1.1.0 Preview版本发布到Windows Server2008 R2 IIS中的各种坑

    Asp.net Core 1.0.1升级到Asp.net Core 1.1.0后,程序无法运行了 解决方案:在project.json中加入runtime节点 "runtimes" ...

  2. C# 6 与 .NET Core 1.0 高级编程 - 40 ASP.NET Core(上)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 40 章  ASP.NET Core(上)),不对的地方欢迎指出与交流. 章节出自<Professiona ...

  3. C# 6 与 .NET Core 1.0 高级编程 - 40 ASP.NET Core(下)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 40 章  ASP.NET Core(下)),不对的地方欢迎指出与交流. 章节出自<Professiona ...

  4. 探索 ASP.Net Core 3.0系列三:ASP.Net Core 3.0中的Service provider validation

    前言:在本文中,我将描述ASP.NET Core 3.0中新的“validate on build”功能. 这可以用来检测您的DI service provider是否配置错误. 具体而言,该功能可检 ...

  5. 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志

    前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...

  6. ASP.NET Core 2.0 MVC 发布部署--------- ASP.NET Core 发布的具体操作

    ASP.NET Core 发布的具体操作 下面使用C# 编写的ASP.NET Core Web项目示例说明发布的全过程. 1.创建项目 选择“文件” > “新建” > “项目”. 在“添加 ...

  7. 简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析

    简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析 虽然经常用 OAuth 2.0,但是原理却不曾了解,印象里觉得很简单,请求跳来跳去,今天看完相关介绍,就来捋一捋 ...

  8. ASP.NET 中OAUTH 2.0 及OPENID CONNECT的介绍

        了解以下内容对ASP.NET 5中的验证中间件应用有很大帮助! OAUTH2是目前很多大型网站都使用的对外提供开放资源接口的应用标准,比入taobao\alipay\腾讯\豆瓣等.它和目前的另 ...

  9. OAuth 2.0、OIDC 原理

    OAuth 目录 OAuth 什么是 OAuth? 为什么是 OAuth? SAML OAuth 和 API OAuth 主要组件 OAuth 作用域 OAuth 参与者 OAuth 令牌 OAuth ...

随机推荐

  1. 【Win 10 应用开发】Sqlite 数据库的简单用法

    如果老周没记错的话,园子里曾经有朋友写过如何在 UWP 项目中使用 Sqlite数据库的文章.目前我们都是使用第三方封装的库,将来,SDK会加入对 Sqlite 的支持. 尽管目前 UWP-RT 库中 ...

  2. IDDD 实现领域驱动设计-理解限界上下文

    上一篇:<IDDD 实现领域驱动设计-理解领域和子域> <实现领域驱动设计>前两章内容,基本上读完了,和<领域驱动设计>不同的是,它把很多的概念都放在前面进行讲述了 ...

  3. 【原创】记一次Project插件开发

    一.开发背景 最近在使用微软的Office Project 2010 进行项目管理,看到排的满满的计划任务,一个个地被执行完毕,还是很有成就感的.其实,不光是在工作中可以使用Project进行项目进度 ...

  4. Swift 必备开发库 (高级篇) (转)

    1.CryptoSwift swift加密库, 支持md5,sha1,sha224,sha256... github地址: https://github.com/krzyzanowskim/Crypt ...

  5. 总结个关于MySQL数据库的问题

    问题概括:MySQL Server has gone away? 遇到这个问题还得追溯到这次前往南通软件园出差.当天下午下班之前,主管说可能明天出差,把项目和最新的数据库备份一下,备份完成之后,也没在 ...

  6. FFmpeg学习1:视频解码

    在视频解码前,先了解以下几个基本的概念: 编解码器(CODEC):能够进行视频和音频压缩(CO)与解压缩(DEC),是视频编解码的核心部分. 容器/多媒体文件(Container/File):没有了解 ...

  7. ASP.NET 中 OutputCache 指令参数详解

    使用@ OutputCache指令使用@ OutputCache指令,能够实现对页面输出缓存的一般性需要.@ OutputCache指令在ASP.NET页或者页中包含的用户控件的头部声明.这种方式非常 ...

  8. App内测神器之蒲公英

    一.前言部分 没使用蒲公英之前一直采用非常傻B的方式给公司App做内部测试,要么发个测试包让公司测试人员用iTUnes 自己安装 要么苦逼的一个个在我Xcode上直接安装测试包,操作起来又麻烦又苦逼, ...

  9. 8 种提升 ASP.NET Web API 性能的方法

    ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没有在应用程序结构设计上花时间来获得很好的执行性能. 在本文中,我将介绍8项提高 ASP.NET Web ...

  10. 记录一次bug解决过程:mybatis中$和#的使用

    一.总结 mybatis中使用sqlMap进行sql查询时,经常需要动态传递参数.动态SQL是mybatis的强大特性之一,也是它优于其他ORM框架的一个重要原因.mybatis在对sql语句进行预编 ...