zoukankan      html  css  js  c++  java
  • Web API使用记录系列(四)OAuth授权与身份校验

      呼,开干第四篇,基于OWIN搭建OAuth认证授权服务器与接口身份校验。

       OAuth包含授权码模式、密码模式、客户端模式和简化模式,这里我们文章记录的是密码模式和客户端模式

      目录

      引用安装

      授权处理-发放Token

        用户名密码授权

        客户端授权

      身份校验-校验失败自定义返回信息

      TestClient增加token获取

      一、引用安装

      除了Owin使用时安装的引用外,还需要安装以下引用  

      Microsoft.Owin.Security.OAuth

      Microsoft.Owin.Security.Cookies

      Microsoft.AspNet.Identity.Owin

      二、搭建授权认证

      修改StartUp,添加关键词partial

      在App_Start下新建StartUp.Auth,同样使用关键词partial,添加ConfiguerAuth,代码如下:

      

     1 public partial class StartUp
     2     {
     3         /// <summary>
     4         /// OAuth配置
     5         /// </summary>
     6         /// <param name="app"></param>
     7         public void ConfigureAuth(IAppBuilder app)
     8         {
     9             app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions
    10             {
    11                 AllowInsecureHttp = true,
    12                 TokenEndpointPath = new PathString("/api/token"),//授权地址
    13                 AccessTokenExpireTimeSpan = TimeSpan.FromHours(24), //过期时间
    14                 AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
    15                 Provider = new SampleAuthorizationServerProvider() //授权服务
    16             });
    17         }
    18     }

      SampleAuthorizationServerProvider是提供授权服务的方法,继承自OAuthAuthorizationServerProvider,包含客户端认证和用户名密码认证,代码如下

     1 /// <summary>
     2     /// 授权服务
     3     /// </summary>
     4     public class SampleAuthorizationServerProvider : OAuthAuthorizationServerProvider
     5     {
     6         #region 客户端授权
     7         /// <summary>
     8         /// 客户端验证
     9         /// </summary>
    10         /// <param name="context"></param>
    11         /// <returns></returns>
    12         public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    13         {
    14             string clientId = "";
    15             string clientSecret = "";
    16             //获取传入的客户端id和客户端校验码
    17             context.TryGetFormCredentials(out clientId, out clientSecret);
    18             if (clientId == "发放的客户端id" && clientSecret == "发放的客户端校验码")
    19             {
    20                 context.Validated(clientId);
    21             }
    22             else
    23             {
    24                 context.SetError("invalid_client", "client is not valid");
    25             }
    26             return base.ValidateClientAuthentication(context);
    27         }
    28 
    29         /// <summary>
    30         /// 客户端授权-生成access token
    31         /// </summary>
    32         /// <param name="context"></param>
    33         /// <returns></returns>
    34         public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
    35         {
    36             var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
    37             oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "app"));//可以继续加一些其它信息
    38             var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties() { AllowRefresh = false });
    39             context.Validated(ticket);
    40             return base.GrantClientCredentials(context);
    41         }
    42         #endregion
    43         
    44         #region 用户名密码授权
    45         public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    46         {
    47             if (context.UserName == "用户名" && context.Password == "用户密码")
    48             {
    49                 var props = new AuthenticationProperties(new Dictionary<string, string>
    50                 {
    51                     {
    52                         "userName", context.UserName
    53                     }
    54                 });
    55                 var identity = new ClaimsIdentity("userinfo");
    56                 identity.AddClaim(new Claim("DisplayName", "张三"));
    57                 identity.AddClaim(new Claim("DutyName", "总监"));
    58 
    59                 var ticket = new AuthenticationTicket(identity, props);
    60 
    61                 context.Validated(ticket);
    62             }
    63             else
    64             {
    65                 context.SetError("invalid_user", "username or password error");
    66             }
    67             return base.GrantResourceOwnerCredentials(context);
    68         }
    69         #endregion
    70 
    71     }

      在根目录App_Start中增加  ConfigureAuth(app);

      请求Token(以客户端验证为示例)

     1           $.ajax({
     2                 url: '/api/token',
     3                 type: 'post',
     4                 data: {
     5                     "grant_type": "client_credentials",
     6                     "client_id": $("#clientid").val(),
     7                     "client_secret": $("#clientscuret").val()
     8                 },
     9                 dataType: "json",
    10                 success: function (data) {
    11                     var accessToken = data.access_token;
    12                     console.log("获取到的token:"+accessToken);
    13                 }
    14             });    

      三、身份认证与身份认证失败自定义返回

      增加身份认证,只需要在需要使用的controller上增加 特性 [Authorize]

      不需要启用验证的使用特性 [AllowAnonymous]

      认证失败返回401,但为了和我们项目的返回数据结构一致,我们需要在认证失败的时候修改返回,新建过滤器继承AuthorizeAttribute,完事将使用Authorized的地方替换为自定义的过滤器

      

     1 public class CustomAuthorizeAttribute:AuthorizeAttribute
     2     {
     3         protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
     4         {
     5             base.HandleUnauthorizedRequest(actionContext);
     6             actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
     7             {
     8                 Content = new StringContent("项目返回的数据格式数据")
     9             };
    10         }
    11     }

      四、TestClient

      为了方便在线测试接口添加token的方便,我们需要给弹出的调用窗口增加authorization的header信息、获取token的操作;并将获取到的token存储到cookie,打开窗口时存在自填充,省去每次的获取操作

      》文件TestClientDialogs文件,在<div class="panel"> 内添加如下代码

      

     1 <div style="margin-bottom:10px;background:#EFEFEF;border:1px solid #ccc;padding:10px">
     2             <div>
     3                 客户端id:
     4                 <input type="text" id="clientid" value="admin" />
     5                 客户端securet:
     6                 <input type="password" id="clinetsecuret" value="admin" />
     7                 <a href='javascript:;' id="btngettk">获取 Token</a>
     8             </div>
     9             <div style="padding:5px;background:#ffd800;" id="getmsg"> <span> 正在获取Token,请稍后...</span></div>
    10         </div>
    11 
    12         <hr />

      》WebApiTestClient.js中修改如下(TestClientViewModel方法末尾添加):

     1 //支持弹出窗口自动填充token
     2         var accessToken;
     3         try {
     4             accessToken = $.cookie("token");
     5         } catch (e) {
     6             console.log(e); 
     7         }
     8         addOrReplaceHeader(self.RequestHeaders, "authorization", "Bearer " + accessToken);
     9         //不存在token时点击获取按钮获取token
    10         $("#getmsg").hide();
    11         $("#btngettk").click(function () {
    12             $("#getmsg").show();
    13             $.ajax({
    14                 url: '/api/token',
    15                 type: 'post',
    16                 data: {
    17                     "grant_type": "client_credentials",
    18                     "client_id": $("#txtusername").val(),
    19                     "client_secret": $("#txtpwd").val()
    20                 },
    21                 dataType: "json",
    22                 success: function (data) {
    23                     var headers = self.RequestHeaders;
    24                     var accessToken = data.access_token;
    25                     $.cookie("token", accessToken, { path: "/", expires: 1 });
    26                     addOrReplaceHeader(headers, "authorization", "Bearer " + accessToken);
    27                     $("#getmsg").hide();
    28                 }
    29             });
    30 
    31         })

      

     本系列使用记录到此,有用到的再补充,有不对的地方希望大家帮忙指正修改,感谢!

  • 相关阅读:
    legend3---2、网站的代码里面的/也是代表根目录
    legend3---PHP使用阿里云短信服务
    legend3---laravel验证码使用
    好用网站推荐
    The practice program of C on point
    Android自己定义组件系列【9】——Canvas绘制折线图
    网络流24题 之十四 孤岛营救问题 分层图
    关于安卓你不知道的6件事
    OpenStack_Swift源代码分析——Ring基本原理及一致性Hash算法
    Codeforces554D:Kyoya and Permutation
  • 原文地址:https://www.cnblogs.com/xihao/p/10630024.html
Copyright © 2011-2022 走看看