grant_type- client_credentials 客户端凭证
- password 密码模式 用于资源所有者密码凭据
- token 隐藏式 、 简化式 简化模式又称为隐式授权码模式,它是授权码模式的一个简化版本
- authorization_code 授权码
客户端凭证认证流程如下:
authorization_code 授权码 认证流程如下
今天着重讲一下关于authorization_code 授权码认证的 C# WebApi 实现过程 StartUp.cs 配置认证接口 public void Configuration(IAppBuilder app) { HttpConfiguration configuration = new HttpConfiguration(); WebApiConfig.Register(configuration); OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = false, AuthenticationMode = AuthenticationMode.Active, AuthorizeEndpointPath = new PathString("/oauth2"), TokenEndpointPath = new PathString(value: "/access_token"), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), Provider = new OpenAuthorizationServerProvider(), AuthorizationCodeProvider = new OpenAuthorizationCodeProvider(), RefreshTokenProvider = new OpenRefreshTokenProvider(), }; configuration.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), DateFormatString = "yyyy-MM-dd HH:mm:ss" };
app.UseOAuthAuthorizationServer(options); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); app.UseCors(CorsOptions.AllowAll); app.UseWebApi(configuration); } OpenAuthorizationServerProvider 需要继承 OAuthAuthorizationServerProvider 实现如下 public class OpenAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) { context.Validated(context.RedirectUri); return base.ValidateClientRedirectUri(context); }
public override async Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context) { if (context.AuthorizeRequest.ClientId.StartsWith("appidstr")) { await Task.Run(() => { context.Validated();}); } else { await Task.Run(() => { context.Rejected(); }); } } public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context) { var redirectUri = context.Request.Query["redirect_uri"]; var clientId = context.Request.Query["client_id"]; var identity = new ClaimsIdentity(new GenericIdentity(clientId,OAuthDefaults.AuthenticationType)); var authorizeCodeContext = new AuthenticationTokenCreateContext(context.OwinContext,context.Options.AuthorizationCodeFormat,new AuthenticationTicket(identity,new AuthenticationProperties(new Dictionary<string, string>{{"client_id", clientId},{"redirect_uri", redirectUri}}){IssuedUtc = DateTimeOffset.UtcNow,ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AccessTokenExpireTimeSpan)})); await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext); context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token)); context.RequestCompleted(); }
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { string clientId, clientSecret; context.TryGetFormCredentials(out clientId, out clientSecret); if (!clientId.StartsWith("appidstr")) { context.SetError("invalid_client", "未授权的客户端"); return Task.FromResult<object>(null); ; } context.Validated(); return Task.FromResult<object>(null); }
public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { return base.GrantClientCredentials(context); } public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { ClaimsIdentity identity = new GenericIdentity(name: context.ClientId, type: OAuthDefaults.AuthenticationType); int userid = 13; string role = "管理员"; string scope = "权限1,权限2"; identity.AddClaim(new Claim("userid", userid.ToString())); identity.AddClaim(new Claim("role", role)); identity.AddClaim(new Claim("scope", scope)); context.Validated(identity); return base.GrantResourceOwnerCredentials(context); } public override async Task ValidateTokenRequest(OAuthValidateTokenRequestContext context) { if (context.TokenRequest.IsAuthorizationCodeGrantType) { await Task.Run(()=>{context.Validated();}); } else { await Task.Run(()=>{context.Rejected();}); } } } PostMan 提交参数 第一步获取 code 第二步,通过 code 换取接口调用凭证 access_token
至此,就完成了 授权码模式的oAuth2认证,当然 access_token 需要客户端保存,根据 expires_in 过期时间刷新,来维持资源访问会话授权。 |