在MVC5 OWin 中间件对 OAuth 提供了比较全面的支持,其中就包括通过客户端 ClientId 与 SecretKey 进行验证的 client credentials 验证方式。
与常见的开放平台登陆机制一致, client credentials验证是作为对服务开放整体服务授权的一种策略。客户端通过 ClientId 与 SecretKey 获得 accessToken 。
client credentials 请求实例:
GET https://mydomain.com/token HTTP/1.1 Content-type:application/x-www-form-urlencoded client_id=987459827985&client_secret=lkfjldsfjkld&grant_type=client_credentials
包含三个参数:
1. client_id
2. client_secret
3. grant_type
下面介绍实现机制
Startup.Auth.cs
默认以 Individual User Accounts 方式创建的MVC5 项目,在 Startup.Auth.cs 文件中会包括以下内容:
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } static Startup() { OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/Token"), Provider = new ApplicationOAuthProvider(), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60), AllowInsecureHttp = true, AuthenticationMode = AuthenticationMode.Active }; } public void ConfigureAuth(IAppBuilder app) { app.UseOAuthBearerTokens(OAuthOptions); }
关于属性的解释:
Token Endpoint Path: does what it says, it is the endpoint you need to call to get a token.
Provider: this instantiates the class for validating and granting tokens, we will be creating the ApplicationOAuthProvider custom class within this post.
AccessTokenExpireTimeSpan: this is the default amount of time a token will last. This can be overridden within the ApplicationOAuthProvider custom class.
AllowInsecureHttp: this just allows non https traffic to get a token, useful during development.
AuthenticationMode: we will be using active authentication in this example.
UseOAuthBearerTokens: The use of bearer token is a pretty standard way of passing tokens within a request header.
在获得 access token 之后,BearerToken 验证请求如下(header 中):
Authorization: Bearer {THE TOKEN}
ApplicationOAuthProvider
下面的内容展示简单的验证实现:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider { private ClientService clientService; public ApplicationOAuthProvider() { this.clientService = new ClientService(); } public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { string clientId; string clientSecret; context.TryGetFormCredentials(out clientId, out clientSecret); if (clientId == "1234" && clientSecret == "12345") { context.Validated(clientId); } return base.ValidateClientAuthentication(context); } public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { var client = clientService.GetClient(context.ClientId); var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName)); var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties()); context.Validated(ticket); return base.GrantClientCredentials(context); } }
方法解释
ValidateClientAuthentication
This method is for validating the input, you can used this method to verify the client id and secret are valid.
The main thing to note is that unless you call context.Validated(clientId), the request will be considered unauthorized.
MSDN 的解释:
通过调用来验证请求的源是否为已注册的“client_id”,以及请求中是否存在该客户端的正确凭据。 如果 Web 应用程序接受基本身份验证凭据,则可以调用 context.TryGetBasicCredentials(out clientId, out clientSecret) 来获取这些值(如果在请求标头中存在)。 如果 Web 应用程序接受“client_id”和“client_secret”作为窗体编码 POST 参数,则可以调用 context.TryGetFormCredentials(out clientId, out clientSecret) 来获取这些值(如果在请求正文中存在)。 如果未调用 context.Validated,则请求将不会继续执行。
GrantClientCredentials
This method is where we will create the client access token.
- First we get the client, we can place values from the client record into the tokens claim collection.
- We then create a new ClaimsIdentity.
- We add some claims, in the example I’ve just added the client name but you can add multiple claims of anything you like into the claims collection.
- Create an AuthenticationTicket using our claims identity.
- Validate the ticket (you do need to do this or the client will be considered unauthenticated)
完整过程
Request a Token
POST http://localhost:19923/Token Content-Type: Application/x-www-form-urlencoded client_id=987459827985&client_secret=lkfjldsfjkld&grant_type=client_credentials
Token Response
{"access_token":"_slaaSSj9UH-UoXaqHMJx4ULscGH-5sKR_qZmuM-TGGQxEGEgB8biMre9-BWrTm2xzzYDRz7IIWgpwjxcRVyvdyLyOPYPJWUy0tsTAoJ8d5Sjn5vvHFrGZrPw1X_XEPhLqvjHzrzK9flR7MLTL8lUH09TwKM08xZsdBj5oTsOTF6LQIrTjluF2oLz_olByG6YO0_hMAMowdVrehA6SCxtA","token_type":"bearer","expires_in":3599}
Call a secured endpoint
By secure, I mean an endpoint that is decorated by the standard Authorize attribute. 也就是通过 accessToken 请求需要授权的资源。
GET http://localhost:19923/MySecuredEndpoint Authorization: Bearer _slaaSSj9UH-UoXaqHMJx4ULscGH-5sKR_qZmuM-TGGQxEGEgB8biMre9-BWrTm2xzzYDRz7IIWgpwjxcRVyvdyLyOPYPJWUy0tsTAoJ8d5Sjn5vvHFrGZrPw1X_XEPhLqvjHzrzK9flR7MLTL8lUH09TwKM08xZsdBj5oTsOTF6LQIrTjluF2oLz_olByG6YO0_hMAMowdVrehA6SCxtA
And We’re Authenticated
Not only that, we also have access to the claims on the server so we can use the claims to personalise or provide authorization rules to our endpoints.
To access the claims, cast the usual principal identity to a claims identity and check out the Claims collection.

公众号近期文章
0 Responses to “MVC5 OAuth 添加 ClientId 与 SecretKey 验证( client credentials 验证)”