首页 > 代码库 > Owin.OAuth

Owin.OAuth

概念

OAuth2四种模式

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

授权码模式

QQ,微信,等方式

技术分享

  • 用户访问客户端,后者将前者导向认证服务器。
  • 用户选择是否给予客户端授权。
  • 假设用户给予授权,认证服务器将用户导向客户端事先指定的”重定向URI”(redirection URI),同时附上一个授权码。
  • 客户端收到授权码,附上早先的”重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
  • 认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

请求

  1. response_type:表示授权类型,必选项,此处的值固定为"code"
  2. client_id:表示客户端的ID,必选项
  3. redirect_uri:表示重定向URI,可选项
  4. scope:表示申请的权限范围,可选项
  5. state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

客户端模式

对于这种方式,试用在 访问一些和用户无关的Open Api,比如一些首页数据,这些数据和用户无关,但是又不想任何人都可以调用这个WebApi,那么就可以采用这种模式。
这个流程很像账号密码模式,但是它认证的是客户端身份,而不是用户

  1. 客户端向认证服务器进行身份认证,并且要求一个访问令牌。
  2. 认证服务器认证无误后,向客户端提供访问令牌。

密码模式

这种模式是很清晰的.就跟传统的验证一样.

  1. 用户(确切的说是客户端)发用户名密码给资源提供者
  2. 资源提供者验证成功后返回访问令牌
  1. grant_type:表示授权类型,此处的值固定为"password",必选项。
  2. username:表示用户名,必选项。
  3. password:表示用户的密码,必选项。
  4. scope:表示权限范围,可选项。

配置

  1. public class Startup
  2. {
  3. public void Configuration(IAppBuilder app)
  4. {
  5. //授权配置
  6. var OAuthOptions = new OAuthAuthorizationServerOptions
  7. {
  8. //获取Token的路径
  9. TokenEndpointPath = new PathString("/Token"),
  10. //自定义的 校验,授权器
  11. Provider = new ApplicationOAuthProvider(),
  12. //我们不想让客户端直接输入凭据,需要一个服务器进行发放授权,这个就像点开QQ第三方登入弹出的登入页面.AuthorizeEndpointPath就是这种页面的地址
  13. AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
  14. //Token 过期时间,默认20分钟
  15. AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
  16. //在生产模式下设 AllowInsecureHttp = false
  17. AllowInsecureHttp = true
  18. };
  19. app.UseOAuthBearerTokens(OAuthOptions);
  20. }
  21. }

通过请求TokenEndpointPath获得Access_Token

自定义OAuthProvider

Owin.OAuth提供的授权方式有

  • GrantAuthorizationCode 授权码模式
  • GrantResourceOwnerCredentials 密码模式
  • GrantClientCredentials 客户端模式
  • GrantCustomExtension 自定义模式,只要grant_type不是上述3个

UseOAuthBearerTokens 内部包含了

  • UseOAuthAuthorizationServer
  • UseOAuthBearerAuthentication

通过基础OAuthAuthorizationServerProvider来定义自己的授权,通过重写上述相应的方法来选择不同的授权模式.这些方法触发条件就是grant_type,不同的值会触发不同的方法.
但在这之前必须经过ValidateClientAuthentication.因为整个流程就是认证->授权,认证是判断这个用户是否是本系统的,授权是给予用户相应的标记,该标记不仅标示用户身份也表示用户的权限.

  1. public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
  2. {
  3. public ApplicationOAuthProvider()
  4. {
  5. }
  6. ///
  7. /// 客户端验证,这是必须通过的方法,确保客户端是正确的,这里通过后才能开始授权
  8. ///
  9. ///
  10. ///
  11. public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
  12. {
  13. //context.TryGetFormCredentials() 从表单中获取clientId,clientSecret
  14. //context.TryGetBasicCredentials 从Authenticate Base解密 获取clientId,lientSecret
  15. //在数据库中查看clientId的有效性
  16. //在这里还没有些clientId,所以下面这句意思是,如果不是使用password认知方式,则直接验证通过,其clientId设置为12
  17. if (context.Parameters["username"] == null && context.Parameters["password"] == null)
  18. {
  19. context.Validated("123");
  20. }
  21. return base.ValidateClientAuthentication(context);
  22. }
  23. ///
  24. /// 账号密码授权,grant_type:password
  25. ///
  26. ///
  27. ///
  28. public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
  29. {
  30. var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
  31. oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
  32. //生成token
  33. var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
  34. context.Validated(ticket);//授权
  35. return base.GrantResourceOwnerCredentials(context);
  36. }
  37. ///
  38. /// 对客户端进行授权,grant_type:client_credentials
  39. ///
  40. ///
  41. ///
  42. public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
  43. {
  44. var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
  45. context.Request.Body.Seek(0, SeekOrigin.Begin);
  46. //从报文体重获取数据
  47. string FormStr = new StreamReader(context.Request.Body).ReadToEnd();
  48. var FormKeyValues = HttpUtility.ParseQueryString(FormStr);
  49. //登入
  50. var loginresult = AsyncHelper.RunSync<LoginOutput>(()=>studentLoginApp.Login(new LoginInput()
  51. {
  52. StuNum = FormKeyValues["StuNum"],
  53. Psw = FormKeyValues["Psw"]
  54. }));
  55. //添加Cookie到声明
  56. oAuthIdentity.AddClaim(new Claim(loginresult.Cookie.Name, loginresult.Cookie.Value));
  57. //添加学号
  58. oAuthIdentity.AddClaim(new Claim(ClaimTypes.UserData, loginresult.StuNum));
  59. //生成token
  60. var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
  61. context.Validated(ticket);
  62. return base.GrantClientCredentials(context);
  63. }
  64. }

这里重写了3个方法
- ValidateClientAuthentication
- GrantResourceOwnerCredentials
- GrantClientCredentials

当请求Access_Token时候必定经过ValidateClientAuthentication,这个通常客户端会带上clientId,lientSecret,在此验证两个数据的正确性,得知该客户端是否有权向本网站申请授权

当通过ValidateClientAuthentication后,则会根据请求中的grant_type来调用GrantResourceOwnerCredentials(password)或GrantClientCredentials(client_credentials)

GrantClientCredentials一般用于普通资源的授权,就是人人都能使用的资源.
GrantResourceOwnerCredentials 则是对用户有要求,需要登入才能使用资源,在这个方法中可以给用户Claim添加数据,比如Role,并再资源上打上Authentication(Role=”“)来限制

获得授权码后调用资源

技术分享
这个是普通资源请求,按理要加上clientId,clientSecret可以直接加到Body中,也可以加到Headers的Authorization
注意这里的Body一定要是x-www-form-urlencoded,否则后端识别不出来,在ajax的时候可能会出问题

  1. _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret)));

如果数据都正确则能获得Access_Token

在这之后的请求需要要把Access_Token添加到Authorization中
技术分享

未学习

  • refresh_token
  • 自定义授权失败响应信息

资料

  • http://www.cnblogs.com/Irving/category/635732.html

Owin.OAuth