客戶端使用本身的名義,而不是用戶的名義,向「服務提供商」 進行認證。html
如何理解這句話? 乍一看,定義有點拗口,剛接觸的童鞋可能徹底不知所云。api
不要緊,咱們先把他的工做流程圖畫出來,以下:服務器
據上圖,能夠得出一個大概的結論app
一、用戶(User)經過客戶端(Client)訪問受限資源(Resource)asp.net
二、由於資源受限,因此須要受權;而這個受權是Client與Authentication之間完成的,能夠說跟User沒有什麼關係ide
三、根據2得出,Resource與User沒有關聯關係,即User不是這個Resource的Owner(全部者)post
既然是這樣,那大概能夠推出這種認證的適用範圍。ui
第一,確定不能用做登陸認證!由於登陸認證後須要獲得用戶的一些基本信息,如暱稱,頭像之類,這些信息是屬於User的;url
第二,適用於一些對於權限要求不強的資源認證,好比:僅用於區分用戶是否登陸,排除匿名用戶獲取資源spa
引用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
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環境搭好了,咱們來運行下試試
認證成功!