基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

时间:2022-09-08 12:55:11

适用范围

前面介绍了Client Credentials Grant ,只适合客户端的模式来使用,不涉及用户相关。而Resource Owner Password Credentials Grant模式中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。这种模式会直接将用户密码暴露给应用程序,因此应谨慎使用。一般说来,只有信任度极高的客户才应授权使用该模式,如官方移动应用、操作系统或高权限程序。


Resource Owner Password Credentials Grant:http://tools.ietf.org/html/rfc6749#section-4.3
     +----------+
| Resource |
| Owner |
| |
+----------+
v
| Resource Owner
(A) Password Credentials
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ------->| |
| | Password Credentials | Authorization |
| Client | | Server |
| |<--(C)---- Access Token ---------<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+ Figure 5: Resource Owner Password Credentials Flow The flow illustrated in Figure 5 includes the following steps: (A) The resource owner provides the client with its username and
password. (B) The client requests an access token from the authorization
server's token endpoint by including the credentials received
from the resource owner. When making the request, the client
authenticates with the authorization server. (C) The authorization server authenticates the client and validates
the resource owner credentials, and if valid, issues an access
token.

基本流程

基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

A. 向用户索要认证信息

首先,我们必须得让用户将认证信息提供给应用程序。对于应用方来说,如果用户处于不可信的网络中时,除了需要输入用户名和密码外,还需要用户提供一个安全令牌作为用户的第三个输入。

B. 交换访问令牌

这里的访问令牌交换过程与授权码类型的验证授权(authorization code)很相似。我们要做的就是向认证服务器提交一个POST请求并在其中提供相应的认证和客户信息。

所需的POST参数:

grant_type 该模式下为"password"

scope 业务访问控制范围,是一个可选参数

client_id 应用注册时获得的客户id

client_secret 应用注册时获得的客户密钥

username 用户的用户名

password 用户的密码

POST https://xxx.com/token HTTP/1.1
Content-type:application/x-www-form-urlencoded
Authorization Basic Base64(clientId:clientSecret) username=irving&password=123456&grant_type=password

C. 刷新Token

1).accesstoken 是有过期时间的,到了过期时间这个 access token 就失效,需要刷新。

2).如果accesstoken会关联一定的用户权限,如果用户授权更改了,这个accesstoken需要被刷新以关联新的权限。

3).为什么要专门用一个 token 去更新 accesstoken 呢?如果没有 refreshtoken,也可以刷新 accesstoken,但每次刷新都要用户输入登录用户名与密码,客户端直接用 refreshtoken 去更新 accesstoken,无需用户进行额外的操作。

POST http://localhost:19923/token
Content-Type: Application/x-www-form-urlencoded
Authorization Basic Base64(clientId:clientSecret) username=irving&password=123456&grant_type=refresh_token

备注:

有了前面相关token,服务调用也很简单

GET https://xxx.com/api/v1/account/profile HTTP/1.1
Content-type:application/x-www-form-urlencoded
Authorization Authorization: Bearer {THE TOKEN}

服务实现

基于ASP.NET WEBAPI Microsoft.Owin.Security.OAuth实现

表设计

CREATE TABLE [dbo].[clients] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[client_name] VARCHAR(200) NOT NULL,
[client_id] VARCHAR (200) NOT NULL,
[client_secret] VARCHAR (500) NOT NULL,
[client_description] NCHAR(10) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
); CREATE TABLE [dbo].[users] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[username] VARCHAR (100) NOT NULL,
[pwd] VARCHAR (500) NULL,
[mobile] VARCHAR (15) NULL,
[birthday] DATETIME NULL,
[sex] INT NULL,
[age] INT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
); CREATE TABLE [dbo].[tokens] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[clientId] VARCHAR (200) NULL,
[userName] VARCHAR (100) NULL,
[accessToken] VARCHAR (300) NULL,
[refreshToken] VARCHAR (300) NULL,
[issuedUtc] DATETIME NULL,
[expiresUtc] DATETIME NULL,
[ipAddress] VARCHAR (50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
仓库设计 
public class AccountRepository : IAccountRepository
{
/// <summary>
/// 验证用户名密码
/// </summary>
/// <param name="userName">用户名</param>
/// <param name="pwd">密码</param>
/// <returns></returns>
public async Task<bool> ValidateUserNameAuthorizationPwdAsync(string userName, string pwd)
{
const string cmdText = @"SELECT COUNT(*) FROM [dbo].[users] WHERE username=@username AND pwd=@pwd";
try
{
return await new SqlConnection(DbSetting.App).ExecuteScalarAsync<int>(cmdText, new { userName = userName, pwd = pwd }) != 0;
}
catch (Exception ex)
{
return false;
}
}
}
public class ClientAuthorizationRepository : IClientAuthorizationRepository
{
/// <summary>
/// 生成OAuth2 clientSecret
/// </summary>
/// <returns></returns>
public async Task<string> GenerateOAuthClientSecretAsync(string client_id = "")
{
return await Task.Run(() =>
{
var cryptoRandomDataGenerator = new RNGCryptoServiceProvider();
byte[] buffer = Guid.NewGuid().ToByteArray();
if (client_id.IsNotNullOrEmpty())
{
buffer = client_id.ToByteArray();
}
cryptoRandomDataGenerator.GetBytes(buffer);
return Convert.ToBase64String(buffer).TrimEnd('=').Replace('+', '-').Replace('/', '_');
});
} /// <summary>
/// 验证客户端[Authorization Basic Base64(clientId:clientSecret)]
/// </summary>
/// <param name="clientId"></param>
/// <param name="clientSecret"></param>
/// <returns></returns>
public async Task<bool> ValidateClientAuthorizationSecretAsync(string client_id, string client_secret)
{
//!!! http://*.com/questions/23652166/how-to-generate-oauth-2-client-id-and-secret
const string cmdText = @"SELECT COUNT(*) FROM [dbo].[clients] WHERE client_id=@clientId AND client_secret=@clientSecret";
try
{
return await new SqlConnection(DbSetting.App).ExecuteScalarAsync<int>(cmdText, new { clientId = client_id, clientSecret = client_secret }) != 0;
}
catch (Exception ex)
{
return false;
}
} /// <summary>
/// 保持票据
/// </summary>
/// <param name="token">票据</param>
/// <returns></returns>
public async Task<bool> SaveTokenAsync(Token token)
{
const string cmdText = @"INSERT INTO Tokens(access_token,token_type, expires_in ,refresh_token ,userName, clientId ,issuedUtc ,expiresUtc) VALUES(@access_token,@token_type, @expires_in ,@refresh_token ,@userName, @clientId ,@issuedUtc ,@expiresUtc)";
try
{
// var data = await new SqlConnection(DbSetting.App).InsertAsync(token);
return await new SqlConnection(DbSetting.App).ExecuteAsync(cmdText, new
{
access_token = token.Access_token,
token_type = token.Token_type,
expires_in = token.Expires_in,
refresh_token = token.Refresh_token,
userName = token.UserName,
clientId = token.ClientId,
issuedUtc = token.IssuedUtc,
expiresUtc = token.ExpiresUtc
}) != 0;
}
catch (Exception ex)
{
return false;
}
}
}

OWIN WEBAPI

        /// <summary>
/// IOS App OAuth2 Credential Grant Password Service
/// </summary>
/// <param name="app"></param>
public void ConfigureAuth(IAppBuilder app)
{
app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions
{
// AccessTokenProvider=
// /token api/v1/account/signin
TokenEndpointPath = new PathString("/token"),
//Provider = new ClientApplicationOAuthProvider(),
//Provider = new PasswordAuthorizationServerProvider(),
//Provider = DependencyInjectionConfig.container.Resolve<PasswordAuthorizationServerProvider>(),
//Provider = DependencyResolver.Current.GetService<PasswordAuthorizationServerProvider>(),
Provider = GlobalConfiguration.Configuration.DependencyResolver.GetRootLifetimeScope().Resolve<PasswordAuthorizationServerProvider>(),
RefreshTokenProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRootLifetimeScope().Resolve<RefreshAuthenticationTokenProvider>(),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),
AuthenticationMode = AuthenticationMode.Active,
//HTTPS is allowed only AllowInsecureHttp = false
#if DEBUG
AllowInsecureHttp = true,
#endif
});

PasswordAuthorizationServerProvider[Password Grant 授权服务]

    /// <summary>
/// Resource Owner Password Credentials Grant 授权
/// </summary>
public class PasswordAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
/// <summary>
/// Password Grant 授权服务
/// </summary>
private readonly IClientAuthorizationService _clientAuthorizationService; /// <summary>
///账户服务
/// </summary>
private readonly IAccountService _accountService; /// <summary>
/// 构造函数
/// </summary>
/// <param name="clientAuthorizationService">Password Grant 授权服务</param>
/// <param name="accountService">用户服务</param>
public PasswordAuthorizationServerProvider(IClientAuthorizationService clientAuthorizationService, IAccountService accountService)
{
_clientAuthorizationService = clientAuthorizationService;
_accountService = accountService;
} /// <summary>
/// 验证客户端 [Authorization Basic Base64(clientId:clientSecret)|Authorization: Basic 5zsd8ewF0MqapsWmDwFmQmeF0Mf2gJkW]
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//var generateClientSecret = await _clientAuthorizationService.GenerateOAuthClientSecretAsync(); //validate client credentials should be stored securely (salted, hashed, iterated)
string clientId;
string clientSecret;
context.TryGetBasicCredentials(out clientId, out clientSecret);
var clientValid = await _clientAuthorizationService.ValidateClientAuthorizationSecretAsync(clientId, clientSecret);
if (!clientValid)
{
//context.Rejected();
context.SetError(AbpConstants.InvalidClient, AbpConstants.InvalidClientErrorDescription);
return;
}
//need to make the client_id available for later security checks
context.OwinContext.Set<string>("as:client_id", clientId);
//context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", _clientAuthorizationProviderService.RefreshTokenLifeTime.ToString());
context.Validated(clientId);
} /// <summary>
/// 验证用户名与密码 [Resource Owner Password Credentials Grant[username与password]|grant_type=password&username=irving&password=654321]
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//validate user credentials (验证用户名与密码) should be stored securely (salted, hashed, iterated)
var userValid = await _accountService.ValidateUserNameAuthorizationPwdAsync(context.UserName, context.Password);
if (!userValid)
{
//context.Rejected();
context.SetError(AbpConstants.AccessDenied, AbpConstants.AccessDeniedErrorDescription);
return;
}
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
var ticket = new AuthenticationTicket(claimsIdentity, new AuthenticationProperties());
context.Validated(ticket);
/*
//create identity
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
claimsIdentity.AddClaim(new Claim("sub", context.UserName));
claimsIdentity.AddClaim(new Claim("role", "user"));
// create metadata to pass on to refresh token provider
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{"as:client_id", context.ClientId }
});
var ticket = new AuthenticationTicket(claimsIdentity, props);
context.Validated(ticket);
*/
} /// <summary>
/// 验证持有 refresh token 的客户端
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
if (context.Ticket == null || context.Ticket.Identity == null)
{
context.Rejected();
return base.GrantRefreshToken(context);
}
var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
var currentClient = context.OwinContext.Get<string>("as:client_id");
// enforce client binding of refresh token
if (originalClient != currentClient)
{
context.Rejected();
return base.GrantRefreshToken(context);
}
// chance to change authentication ticket for refresh token requests
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{ "as:client_id", context.ClientId }
});
var newTicket = new AuthenticationTicket(claimsIdentity, props);
context.Validated(newTicket);
return base.GrantRefreshToken(context);
}
}

RefreshAuthenticationTokenProvider[刷新Token]

/// <summary>
/// 刷新Token
/// </summary>
public class RefreshAuthenticationTokenProvider : AuthenticationTokenProvider
{
private readonly ConcurrentDictionary<string, string> _authenticationCodes = new ConcurrentDictionary<string, string>(StringComparer.Ordinal); /// <summary>
/// Password Grant 授权服务
/// </summary>
private readonly IClientAuthorizationService _clientAuthorizationService; /// <summary>
/// 构造函数
/// </summary>
/// <param name="clientAuthorizationService">Password Grant 授权服务</param>
public RefreshAuthenticationTokenProvider(IClientAuthorizationService clientAuthorizationService)
{
_clientAuthorizationService = clientAuthorizationService;
} /// <summary>
/// 创建refreshToken
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task CreateAsync(AuthenticationTokenCreateContext context)
{
if (string.IsNullOrEmpty(context.Ticket.Identity.Name)) return;
var clietId = context.OwinContext.Get<string>("as:client_id");
if (string.IsNullOrEmpty(clietId)) return;
var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");
//if (string.IsNullOrEmpty(refreshTokenLifeTime)) return; string ip = context.Request.RemoteIpAddress;
int? port = context.Request.RemotePort;
var token = new Token()
{
ClientId = clietId,
UserName = context.Ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddSeconds(Convert.ToDouble(refreshTokenLifeTime)),
};
context.Ticket.Properties.IssuedUtc = token.IssuedUtc;
context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;
token.Access_token = context.SerializeTicket();
token.Refresh_token = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '-').Replace('/', '_');
if (await _clientAuthorizationService.SaveTokenAsync(token))
{
context.SetToken(token.Refresh_token);
}
/*
// maybe only create a handle the first time, then re-use for same client
// copy properties and set the desired lifetime of refresh token
var tokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
{
IssuedUtc = context.Ticket.Properties.IssuedUtc,
ExpiresUtc = context.Ticket.Properties.ExpiresUtc
};
var token = context.SerializeTicket();
var refreshTicket = new AuthenticationTicket(context.Ticket.Identity, tokenProperties);
_refreshTokens.TryAdd(token, refreshTicket);
// consider storing only the hash of the handle
context.SetToken(token);
*/
} /// <summary>
/// 刷新refreshToken[刷新access token时,refresh token也会重新生成]
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
string token = context.Token;
string value;
if (_authenticationCodes.TryRemove(context.Token, out value))
{
context.DeserializeTicket(value);
}
return base.ReceiveAsync(context);
}

DI[DependencyInjectionConfig]

 //注册 Password Grant 授权服务
builder.RegisterType<PasswordAuthorizationServerProvider>().AsSelf().SingleInstance();
builder.RegisterType<RefreshAuthenticationTokenProvider>().AsSelf().SingleInstance();

启用验证不记名授权[WebApiConfig]

    // Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

资源服务[AccountController]

    /// <summary>
/// 账户控制器
/// </summary>
[RoutePrefix("api/v1/account")]
public class AccountController : ApiController
{
/// <summary>
/// 用户登录
/// </summary>
/// <returns></returns>
[Authorize]
[Route("signin")]
public async Task<IHttpActionResult> SignInAsync(LoginViewModel lg)
{
return Ok(new { IsError = true, Msg = string.Empty, Data = string.Empty });
} /// <summary>
/// 用户信息
/// </summary>
/// <returns></returns>
[Authorize]
[Route("info")]
public async Task<IHttpActionResult> InfoAsync()
{
return Ok(new { IsError = true, Msg = "irving", Data = string.Empty });
} [Authorize]
[HttpGet]
[Route("api/account/profile")]
public HttpResponseMessage Profile()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ObjectContent<object>(new
{
UserName = User.Identity.Name
}, Configuration.Formatters.JsonFormatter)
};
}

客户端

获得票据

服务端[/token]获取token需要三个参数+ Basic Authorzation BASE64(client_id+client_secret)

POST https://domain.com/token HTTP/1.1

Content-type:application/json;charset=UTF-8

Authorization: Basic Base64(clientId:clientSecret)

username=irving&password=123456&grant_type=password

    {

        "access_token": "uqoRNxKiC5tdNkD-Q8z2RRW98O8j2ZXf2RsQLd0x0IpaZJexQBeH67mRHFqyU4bwRd5nZLdOg-akEOwQRJaDBGkAqpi0tTvsqHU7EsEdNuS6SNugVQX6FTVSBmvVSJhuXmQeZBBiUl-20ZgxLFF4gpKD5HiNIuOG0ZPHAt-dNXV22e3i4hdhL-KoNMAf6xIF0Rx-18syravzRTPMtCoIcA",

        "token_type": "bearer",

        "expires_in": 7199,

        "refresh_token": "h6Bwe_hNljTubhqhmXCK8A"

    }

基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

刷新票据

POST https://domain.com/token HTTP/1.1

Content-type:application/json;charset=UTF-8

Authorization: Basic Base64(clientId:clientSecret)

grant_type=refresh_token&refresh_token=h6Bwe_hNljTubhqhmXCK8A

    {

        "access_token": "rw_W_xic8xNlGd1kW06QiDLfXibmMPzUFAlSQx0jZ6KUcLq7bxMBBnI8ttITuhp1exus2wLOOgJ-bOzXz4y11fvbm9Do1rUiwYNvsbBFBsMnut2PYsC_6mBlFkUCYTaEZVhEwtopP_9cAVmC4G-UonQTsQ943ejtiLLc6nYQqVQvYe_0tndRxz2uBuLdc_KNcavs8AVq5QlAjCmozvZC1g",

        "token_type": "bearer",

        "expires_in": 7199,

        "refresh_token": "enGVqAraNTgv8EpjCxszMA"

    }

基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

请求资源

设置HTTP头 Authorization: Bearer {THE TOKEN}

POST https://domain.com//api/v1/account/info HTTP/1.1

Content-type:application/json;charset=UTF-8

Authorization: Bearer rw_W_xic8xNlGd1kW06QiDLfXibmMPzUFAlSQx0jZ6KUcLq7bxMBBnI8ttITuhp1exus2wLOOgJ-bOzXz4y11fvbm9Do1rUiwYNvsbBFBsMnut2PYsC_6mBlFkUCYTaEZVhEwtopP_9cAVmC4G-UonQTsQ943ejtiLLc6nYQqVQvYe_0tndRxz2uBuLdc_KNcavs8AVq5QlAjCmozvZC1g

    {

        "IsError": true,

        "Msg": "irving",

        "Data": ""

    }

基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

Code Test

基础代码Test

   [RoutePrefix("api/v1/oauth")]
public class OAuthController : ApiController
{
/// <summary>
/// 获取token
/// </summary>
/// <returns></returns>
[Route("token")]
public async Task<IHttpActionResult> GetTokenAsync()
{
//获得token
var dict = new SortedDictionary<string, string>();
dict.Add("grant_type", "password");
dict.Add("username", "irving");
dict.Add("password", "123456");
//var data = await (@"http://" + Request.RequestUri.Authority + @"/token").WithHeader("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes("irving" + ":" + "123456"))).PostUrlEncodedAsync(dict).ReceiveJson<PToken>();
//var order = await (@"http://" + Request.RequestUri.Authority + @"/api/v1/oauth/order").WithHeader("Authorization", "Bearer " + data.access_token).GetAsync().ReceiveString();
var data = await (@"http://" + Request.RequestUri.Authority + @"/token").WithBasicAuth("irving", "123456").PostUrlEncodedAsync(dict).ReceiveJson<PToken>();
var order = await (@"http://" + Request.RequestUri.Authority + @"/api/v1/oauth/order").WithOAuthBearerToken(data.access_token).GetAsync().ReceiveString();
return Ok(new { IsError = true, Msg = order, Data = data });
} /// <summary>
/// 获得订单信息
/// </summary>
/// <returns></returns>
[Authorize]
[Route("order")]
public async Task<IHttpActionResult> GetOrderAsync()
{
string username = User.Identity.Name;
var authentication = HttpContext.Current.GetOwinContext().Authentication;
var ticket = authentication.AuthenticateAsync("Bearer").Result;
return Ok(new { IsError = true, Msg = string.Empty, Data = Thread.CurrentPrincipal.Identity.Name + " It's about news !!! token expires: " + ticket.Properties.Dictionary.ToJson() });
}
}
public class PToken
{
public string access_token { get; set; }
public string refresh_token { get; set; }
public string token_type { get; set; }
public string expires_in { get; set; }
}

GitHub

https://github.com/zhouyongtao/App.WebAPI

Share PDF

分享一个PDF Securing ASP.NET Web APIs

http://sddconf.com/brands/sdd/library/Securing_ASPdotNET_web_APIs.pdf

Refer:

OpenID Connect Provider and OAuth2 Authorization Server Framework

https://github.com/IdentityServer/IdentityServer3

Chapter 16. The OAuth 2.0 Authorization Framework

http://chimera.labs.oreilly.com/books/1234000001708/ch16.html

Token Based Authentication using ASP.NET Web API 2, Owin, and Identity

http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/?utm_source=tuicool

Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin

http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/

Creating an OAuth password grant type token endpoint

http://www.hackered.co.uk/articles/asp-net-mvc-creating-an-oauth-password-grant-type-token-endpoint

Token Based Authentication in Web API 2

http://www.c-sharpcorner.com/UploadFile/736ca4/token-based-authentication-in-web-api-2/

Adding Refresh Tokens to a Web API v2 Authorization Server

http://leastprivilege.com/2013/11/15/adding-refresh-tokens-to-a-web-api-v2-authorization-server/

RESTful API With Node.js + MongoDB

http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb

Beer Locker: Building a RESTful API With Node - OAuth2 Server

http://scottksmith.com/blog/2014/07/02/beer-locker-building-a-restful-api-with-node-oauth2-server

http://scottksmith.com/blog/2014/05/29/beer-locker-building-a-restful-api-with-node-passport/

http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server

http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api

How to implement oauth2 server in ASP.NET MVC 5 and WEB API 2

http://*.com/questions/26755573/how-to-implement-oauth2-server-in-asp-net-mvc-5-and-web-api-2

基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】的更多相关文章

  1. 基于 IdentityServer3 实现 OAuth 2&period;0 授权服务【密码模式&lpar;Resource Owner Password Credentials&rpar;】

    密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码.客户端使用这些信息,向"服务商提供商"索要授权 ...

  2. 使用Resource Owner Password Credentials Grant授权发放Token

    对应的应用场景是:为自家的网站开发手机 App(非第三方 App),只需用户在 App 上登录,无需用户对 App 所能访问的数据进行授权. 客户端获取Token: public string Get ...

  3. OAuth2&period;0学习(1-6)授权方式3-密码模式(Resource Owner Password Credentials Grant)

    授权方式3-密码模式(Resource Owner Password Credentials Grant) 密码模式(Resource Owner Password Credentials Grant ...

  4. (转)基于OWIN WebAPI 使用OAuth授权服务【客户端模式&lpar;Client Credentials Grant&rpar;】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  5. 基于OWIN WebAPI 使用OAuth授权服务【客户端模式&lpar;Client Credentials Grant&rpar;】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  6. Oauth2&period;0(六):Resource Owner Password Credentials 授权和 Client Credentials 授权

    这两种简称 Password 方式和 Client 方式吧,都只适用于应用是受信任的场景.一个典型的例子是同一个企业内部的不同产品要使用本企业的 Oauth2.0 体系.在有些情况下,产品希望能够定制 ...

  7. OAuth密码模式说明(resource owner password credentials)

    用户向客户端(third party application)提供用户名和密码. 客户端将用户名和密码发给认证服务器(Authorization server),向后者请求令牌(token). 认证服 ...

  8. asp&period;net权限认证:OWIN实现OAuth 2&period;0 之密码模式(Resource Owner Password Credential)

    asp.net权限认证系列 asp.net权限认证:Forms认证 asp.net权限认证:HTTP基本认证(http basic) asp.net权限认证:Windows认证 asp.net权限认证 ...

  9. OAuth2&period;0学习(1-7)授权方式4-客户端模式(Client Credentials Grant)

    授权方式4-客户端模式(Client Credentials Grant) 客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提 ...

随机推荐

  1. 编写&period;gitignore文件的几个小技巧

    记录几个编写.gitignore文件的小技巧,可能你早就知道了,但我是google了一番才找到写法. 忽略所有名称为bin的文件夹 bin/ 只忽略第一级目录中,名称为bin的文件夹 /bin/ 忽略 ...

  2. exp导出做成批处理注意事项

    不能叫exp.bat,会一直显示导出这句话. 出现EXP-00106: 数据库链接口令无效:是因为http://blog.csdn.net/hzfu007/article/details/189823 ...

  3. 【tornado】系列项目(一)之基于领域驱动模型架构设计的京东用户管理后台

    本博文将一步步揭秘京东等大型网站的领域驱动模型,致力于让读者完全掌握这种网络架构中的“高富帅”. 一.预备知识: 1.接口: python中并没有类似java等其它语言中的接口类型,但是python中 ...

  4. UNION 查询中的排序

    MSSQL 不允许在UNION查询中使用 ORDER BY 因此,当我们需要这种功能的时候,就需要绕一些弯路. 比如有一张学生表student 和教师表 teacher , 我们要查询所有的教师学生的 ...

  5. Mac下使用Automator实现隐藏和显示

    本文使用Makdown编辑 通常系统中打开一个文件有好多种方法,编辑也是.例如你要打开OmniGraffle来画个图(suppose you are working on the Mac OS X) ...

  6. Akka&period;NET

    https://github.com/akkadotnet Akka是什么? 可扩展的分布式实时事务处理 编写正确的并发,容错和可扩展的应用程序是太难了.大多数时候,这是因为我们使用了错误的工具和错误 ...

  7. HTML 的 iframe 元素

    在 HTML 中, iframe 元素用于在网页中嵌入其它网页的内容,例如: <iframe src="http://example.com/abc.html">ifr ...

  8. 第一个Windows程序讲解

    上次,我们一起写了第一个Windows程序,虽然程序非常简单,但是它却可以帮助大家建立学好windows开发的信心. 今天,就让我帮助大家分析一下这个程序的内容.首先,我们的程序包含了一个头文件:wi ...

  9. vs2015管理github代码

  10. Epicor系统二次开发

    Epicor系统二次开发 一.获取或修改界面EpiDataView的字段数据(Get EpiDataView data) C# EpiDataView edv = (EpiDataView)oTran ...