客戶端模式定義
客戶端使用自己的名義,而不是用戶的名義,向“服務提供商” 進行認證。
如何理解這句話? 乍一看,定義有點拗口,剛接觸的童鞋可能完全不知所雲。
沒關系,我們先把他的工作流程圖畫出來,如下:

據上圖,可以得出一個大概的結論
1、用戶(User)通過客戶端(Client)訪問受限資源(Resource)
2、因為資源受限,所以需要授權;而這個授權是Client與Authentication之間完成的,可以說跟User沒有什么關系
3、根據2得出,Resource與User沒有關聯關系,即User不是這個Resource的Owner(所有者)
既然是這樣,那大概可以推出這種認證的適用范圍。
第一,肯定不能用作登錄認證!因為登錄認證后需要得到用戶的一些基本信息,如昵稱,頭像之類,這些信息是屬於User的;
第二,適用於一些對於權限要求不強的資源認證,比如:僅用於區分用戶是否登錄,排除匿名用戶獲取資源
新建一個資源項目:ResourceServer

引用owin:install-package Microsoft.Owin -Version 2.1.0
新增Startup.cs
[assembly: OwinStartup(typeof(ResourceServer.Startup))]
namespace ResourceServer
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
新增Startup.Auth.cs
namespace ResourceServer
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// 這句是資源服務器認證token的關鍵,認證邏輯在里邊封裝好了,我們看不到
app.UseOAuthBearerAuthentication(new Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationOptions());
}
}
}
新增ValuesController.cs
namespace ResourceServer.Controllers
{
[Authorize]
public class ValuesController : ApiController
{
public string Get()
{
return "lanxiaoke";
}
}
}
新建認證服務項目

修改Startup.Auth.cs
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// Setup Authorization Server
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/OAuth/Token"),
ApplicationCanDisplayErrors = true,
#if DEBUG
AllowInsecureHttp = true,
#endif
// Authorization server provider which controls the lifecycle of Authorization Server
Provider = new OAuthAuthorizationServerProvider
{
OnValidateClientAuthentication = ValidateClientAuthentication,
OnGrantClientCredentials = GrantClientCredetails
},
// Authorization code provider which creates and receives authorization code
AuthorizationCodeProvider = new AuthenticationTokenProvider
{
OnCreate = CreateAuthenticationCode,
OnReceive = ReceiveAuthenticationCode,
},
// Refresh token provider which creates and receives referesh token
RefreshTokenProvider = new AuthenticationTokenProvider
{
OnCreate = CreateRefreshToken,
OnReceive = ReceiveRefreshToken,
}
});
}
private Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
if (context.TryGetBasicCredentials(out clientId, out clientSecret) ||
context.TryGetFormCredentials(out clientId, out clientSecret))
{
if (clientId == "123456" && clientSecret == "abcdef")
{
context.Validated();
}
}
return Task.FromResult(0);
}
private Task GrantClientCredetails(OAuthGrantClientCredentialsContext context)
{
var identity = new ClaimsIdentity(new GenericIdentity(context.ClientId, OAuthDefaults.AuthenticationType), context.Scope.Select(x => new Claim("urn:oauth:scope", x)));
context.Validated(identity);
return Task.FromResult(0);
}
private readonly ConcurrentDictionary<string, string> _authenticationCodes =
new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
private void CreateAuthenticationCode(AuthenticationTokenCreateContext context)
{
context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
_authenticationCodes[context.Token] = context.SerializeTicket();
}
private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context)
{
string value;
if (_authenticationCodes.TryRemove(context.Token, out value))
{
context.DeserializeTicket(value);
}
}
private void CreateRefreshToken(AuthenticationTokenCreateContext context)
{
context.SetToken(context.SerializeTicket());
}
private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}
}
自此,認證服務項目算是建好了,因為對於客戶端模式,認證服務器只需要返回token
新增Client項目

static void Main(string[] args)
{
var authorizationServerUri = new Uri("http://localhost:8270/");
var authorizationServerDescription = new AuthorizationServerDescription
{
TokenEndpoint = new Uri(authorizationServerUri, "OAuth/Token")
};
var client = new WebServerClient(authorizationServerDescription, "123456", "abcdef");
var state = client.GetClientAccessToken(new[] { "scopes1", "scopes2" });
var token = state.AccessToken;
Console.WriteLine("Token: {0}", token);
var resourceServerUri = new Uri("http://localhost:8001/");
var httpClient = new HttpClient(client.CreateAuthorizingHandler(token));
var values = httpClient.GetStringAsync(new Uri(resourceServerUri, "api/Values")).Result;
Console.WriteLine("Result: {0}", values);
Console.ReadKey();
}
OK,Client環境搭好了,我們來運行下試試

認證成功!
asp.net權限認證系列
- asp.net權限認證:Forms認證
- asp.net權限認證:HTTP基本認證(http basic)
- asp.net權限認證:Windows認證
- asp.net權限認證:摘要認證(digest authentication)
- asp.net權限認證:OWIN實現OAuth 2.0 之客戶端模式(Client Credential)
- asp.net權限認證:OWIN實現OAuth 2.0 之密碼模式(Resource Owner Password Credential)
- asp.net權限認證:OWIN實現OAuth 2.0 之授權碼模式(Authorization Code)
- asp.net權限認證:OWIN實現OAuth 2.0 之簡化模式(Implicit)
