2020-08-06

IdentityServer4 静默刷新(Implicit)

写在前面

1、源码(.Net Core 2.2)

  git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git

2、相关章节

  2.1、《IdentityServer4 (1) 客户端授权模式(Client Credentials)》
  2.2、《IdentityServer4 (2) 密码授权(Resource Owner Password)》
  2.3、《IdentityServer4 (3) 授权码模式(Authorization Code)》
  2.4、《IdentityServer4 (4) 静默刷新(Implicit)》
  2.5、《IdentityServer4 (5) 混合模式(Hybrid)》

3、参考资料

  IdentityServer4 中文文档 />   IdentityServer4 英文文档 https://identityserver4.readthedocs.io/en/latest/
  OpenID Connect 官网 https://openid.net/connect/
  OpenID Connect 中文 https://www.cnblogs.com/linianhui/p/openid-connect-core.html
  OpenID Connect和OAuth 2.0对比:https://www.jianshu.com/p/d453076e6433
  Oauth 2.0 官网:https://oauth.net/2/
  Oauth 2.0 授权框架:https://tools.ietf.org/html/rfc6749#section-4.2.1

4、流程图

  1、客户端准备一个包含所需请求参数的身份验证请求。
  2、客户端将请求发送到授权服务器(填写账号密码)。
  3、授权服务器对最终用户进行身份验证(验证账号密码和客户端)。
  4、授权服务器获得最终用户同意/授权。
  5、授权服务器使用IdToken和AccessToken(如果要求)将最终用户发送回客户端。

一、服务端

1、添加客户端

 new Client{  ClientId="mvc client implicit", //客户端Id  ClientName="测试客户端 Implicit", //客户端名称 随便写  //Implicit 模式 因为token 是通过浏览器发送给客户端的,这里必须启用  AllowAccessTokensViaBrowser=true,  AllowedGrantTypes=GrantTypes.Implicit,//验证模式   RedirectUris = {   "",   // AccessToken 有效期比较短,刷新 AccessToken 的页面   "",  },  //是否需要用户点击同意,这里需要设置为 false,不然客户端静默刷新不可用  RequireConsent=false,  AllowedCorsOrigins={ "" },  //注销重定向的url  PostLogoutRedirectUris = { "" },  AccessTokenLifetime=10,  //客户端访问权限  AllowedScopes =  {   "api1",   IdentityServerConstants.StandardScopes.OpenId,   IdentityServerConstants.StandardScopes.Email,   IdentityServerConstants.StandardScopes.Address,   IdentityServerConstants.StandardScopes.Phone,   IdentityServerConstants.StandardScopes.Profile  } },

二、客户端

1、下载 oidc-client 库

  git地址:https://github.com/IdentityModel/oidc-client-js 

2、添加测试页面

  我直接使用的/home/index 在里面添加请求授权代码

<style> .box {  height: 200px;  overflow: auto;  border: 1px solid #ccc } .btn-box {  margin-top: 10px; }  .btn-box button {   margin-right: 10px;  }</style><div class="row btn-box"> <button class="btn btn-primary" onclick="login()">登陆 Implicit</button> <button class="btn btn-primary" onclick="getuser()">获取 User Implicit</button> <button class="btn btn-primary" onclick="getapi()">测试 API Implicit</button> <button class="btn btn-primary" onclick="removeUser()">清除 User Implicit</button> <button class="btn btn-primary" onclick="iframeSignin()">刷新 User Implicit</button></div><hr /><div class="row"> <h3>User:</h3> <div id="userinfo" class="col-md-12 box"> </div></div><div class="row"> <h3>API:</h3> <div id="apiresult" class="col-md-12 box"> </div></div>@section Scripts{ <script src="~/lib/oidc/oidc-client.min.js"></script> <script type="text/javascript">  Oidc.Log.logger = window.console;  Oidc.Log.level = Oidc.Log.DEBUG;  var log = function (msg) { console.log(msg); }  var testconfig = {   authority: "",   client_id: "mvc client implicit",   redirect_uri: "",   response_type: "id_token token",   scope: "api1 openid email phone address profile",   clockSkew: 0,   //启用静默刷新token   silent_redirect_uri: "",   automaticSilentRenew: true,  };  var mgr = new Oidc.UserManager(testconfig);  mgr.events.addUserLoaded(function (user) {   console.log("user loaded", user);   mgr.getUser().then(function () {    console.log("getUser loaded user after userLoaded event fired");   });  });  mgr.events.addUserUnloaded(function () {   console.log("user unloaded");  });  mgr.events.addAccessTokenExpiring(function () {   log("Access token expiring..." + new Date());  });  mgr.events.addSilentRenewError(function (err) {   log("Silent renew error: " + err.message);  });  mgr.events.addUserSignedOut(function () {   log("User signed out of OP");   mgr.removeUser();  });  var login = function () {   mgr.signinRedirect();  };  var getuser = function () {   mgr.getUser().then(function (user) {    log("got user");    $('#userinfo').html(JSON.stringify(user));   }).catch(function (err) {    log(err);   });  };  var removeUser = function () {   mgr.removeUser().then(function () {    log("user removed");   }).catch(function (err) {    log(err);   });  }  var iframeSignin = function () {   mgr.signinSilent().then(function (user) {    log("signed in", user);   }).catch(function (err) {    log(err);   });  }  var getapi = function (token) {   mgr.getUser().then(function (user) {    log("get user success");    document.getElementById('userinfo').innerHTML = JSON.stringify(user);    var settings = {     url: '',     beforeSend: function (xhr) {      xhr.setRequestHeader('Authorization', 'Bearer ' + user.access_token)      console.log("beforeSend", xhr)     },     success: function (res) {      console.log("api result success:", res);      $('#apiresult').html(JSON.stringify(res));     }, error: function (res) {      console.log("api result error:", res);      $('#apiresult').html(res.responseText);     }    }    $.ajax(settings);   }).catch(function (err) {    log(err);   });  };  </script>}

3、登陆回调页面

<!DOCTYPE html><html><head> <meta charset="utf-8" /> <title>Oidc-Client</title> <script src="lib/oidc/oidc-client.min.js"></script></head><body> 登陆中...</body></html><script> new Oidc.UserManager().signinRedirectCallback().then(function (user) {  //console.log("signin response success");  //console.log(user)  //document.getElementById("message").innerText = JSON.stringify(user);  location.href = "/home"; }).catch(function (err) {  console.log(err); });</script>

4、自动刷新页面

<!DOCTYPE html><html><head> <meta charset="utf-8" /> <title>Oidc-Client</title></head><body> <h1>Silent.html</h1></body></html><script src="lib/oidc/oidc-client.min.js"></script><script> new Oidc.UserManager().signinSilentCallback()  .catch((err) => {   console.log("refresh", err);  });</script>

5、页面结构目录

  

三、API资源

1、修改StartUp.cs

ConfigureServices()

 services.AddCors(options => {  options.AddPolicy("client1", policy =>  {   //客户端地址   policy.WithOrigins("");   policy.AllowAnyHeader();   policy.AllowAnyMethod();  }); }); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => {  // IdentityServer 地址  options.Authority = "";  //不需要https  options.RequireHttpsMetadata = false;  //这里要和 IdentityServer 定义的 api1 保持一致  options.Audience = "api1";  //token 默认容忍5分钟过期时间偏移,这里设置为0,  //这里就是为什么定义客户端设置了过期时间为5秒,过期后仍可以访问数据  options.TokenValidationParameters.ClockSkew = TimeSpan.Zero;  options.Events = new JwtBearerEvents  {   //AccessToken 验证失败   OnChallenge = op =>   {    //跳过所有默认操作    op.HandleResponse();    //下面是自定义返回消息    //op.Response.Headers.Add("token", "401");    op.Response.ContentType = "application/json";    op.Response.StatusCode = StatusCodes.Status401Unauthorized;    op.Response.WriteAsync(JsonConvert.SerializeObject(new    {     status = StatusCodes.Status401Unauthorized,     msg = "token无效",     error = op.Error    }));    return Task.CompletedTask;   }  }; });

Configure()

 app.UseStaticFiles(); //这里注意 一定要在 UseMvc前面,顺序不可改变 app.UseAuthentication(); app.UseCors("client1");

三、测试  

  可以看到右侧console 再自动刷新

IdentityServer4 静默刷新(Implicit)草根卖家俱乐部2017年度盛典rakuten物流配送YouTube广告 || 一次性让你了解个够!独霸美国电商市场!美国大小零售商越来越忌惮亚马逊 菲律宾海关出新规定啦!违规者轻则影响清关重则罚款!西冲烧烤场地费需要多少钱?锦绣中华春节期间有什么活动?西冲海滩附近有没有地铁站?

No comments:

Post a Comment