Webapi 2.0 如何在访问令牌过期时实现刷新 JWT 令牌
Webapi 2.0 how to implement refresh JWT token when access token expired
我在 web API 实现方面相当陌生,我创建了一个 web API 服务以将其与 ASP.net web form
应用程序以及一些独立应用程序一起使用(C# Console/Windows 应用程序)使用 HttpClient
object.
我已经在 web api 中实现了一个具有过期时间限制的基本 JWT 访问令牌身份验证,这种身份验证技术在令牌未过期之前工作正常,当令牌过期时 web api 不接受作为令牌的请求已过期!根据身份验证实现,这很好,但我想在 web api 中实现刷新令牌逻辑,因此令牌可以 renew/refersh 并且客户端应该能够使用 web api 资源。
我在谷歌上搜索了很多但无法找到刷新令牌逻辑的正确实现。如果有人有正确的方法来处理过期的访问令牌,请帮助我。
以下是我在 asp.net 应用程序中使用网络 api 所遵循的步骤。
在 ASP.net web 表单登录页面我调用了 web API "TokenController" 这个控制器有两个参数 loginID 和 password 以及 return JWT我存储在 session object 中的令牌。
现在,每当我的客户端应用程序也需要使用 Web api 资源时,在调用 Web api 时,资源必须在请求 header 中发送访问令牌httpclient
.
但是当令牌过期时,客户端无法使用网络 api 资源,他必须重新登录并更新令牌!这是我不想要的,用户不应提示再次登录,因为应用程序 session 超时尚未结束。
如何在不强制用户重新登录的情况下刷新令牌。
如果我下面给出的 JWT 访问令牌实现逻辑不合适或者不正确,请告诉我正确的方法。
代码如下
WebAPI
AuthHandler.cs
public class AuthHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage errorResponse = null;
try
{
IEnumerable<string> authHeaderValues;
request.Headers.TryGetValues("Authorization", out authHeaderValues);
if (authHeaderValues == null)
return base.SendAsync(request, cancellationToken);
var requestToken = authHeaderValues.ElementAt(0);
var token = "";
if (requestToken.StartsWith("Bearer ", StringComparison.CurrentCultureIgnoreCase))
{
token = requestToken.Substring("Bearer ".Length);
}
var secret = "w$e$#*az";
ClaimsPrincipal cp = ValidateToken(token, secret, true);
Thread.CurrentPrincipal = cp;
if (HttpContext.Current != null)
{
Thread.CurrentPrincipal = cp;
HttpContext.Current.User = cp;
}
}
catch (SignatureVerificationException ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex.Message);
}
catch (Exception ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
}
return errorResponse != null
? Task.FromResult(errorResponse)
: base.SendAsync(request, cancellationToken);
}
private static ClaimsPrincipal ValidateToken(string token, string secret, bool checkExpiration)
{
var jsonSerializer = new JavaScriptSerializer();
string payloadJson = string.Empty;
try
{
payloadJson = JsonWebToken.Decode(token, secret);
}
catch (Exception)
{
throw new SignatureVerificationException("Unauthorized access!");
}
var payloadData = jsonSerializer.Deserialize<Dictionary<string, object>>(payloadJson);
object exp;
if (payloadData != null && (checkExpiration && payloadData.TryGetValue("exp", out exp)))
{
var validTo = AuthFactory.FromUnixTime(long.Parse(exp.ToString()));
if (DateTime.Compare(validTo, DateTime.UtcNow) <= 0)
{
throw new SignatureVerificationException("Token is expired!");
}
}
var clmsIdentity = new ClaimsIdentity("Federation", ClaimTypes.Name, ClaimTypes.Role);
var claims = new List<Claim>();
if (payloadData != null)
foreach (var pair in payloadData)
{
var claimType = pair.Key;
var source = pair.Value as ArrayList;
if (source != null)
{
claims.AddRange(from object item in source
select new Claim(claimType, item.ToString(), ClaimValueTypes.String));
continue;
}
switch (pair.Key.ToUpper())
{
case "USERNAME":
claims.Add(new Claim(ClaimTypes.Name, pair.Value.ToString(), ClaimValueTypes.String));
break;
case "EMAILID":
claims.Add(new Claim(ClaimTypes.Email, pair.Value.ToString(), ClaimValueTypes.Email));
break;
case "USERID":
claims.Add(new Claim(ClaimTypes.UserData, pair.Value.ToString(), ClaimValueTypes.Integer));
break;
default:
claims.Add(new Claim(claimType, pair.Value.ToString(), ClaimValueTypes.String));
break;
}
}
clmsIdentity.AddClaims(claims);
ClaimsPrincipal cp = new ClaimsPrincipal(clmsIdentity);
return cp;
}
}
AuthFactory.cs
public static class AuthFactory
{
internal static DateTime FromUnixTime(double unixTime)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddSeconds(unixTime);
}
internal static string CreateToken(User user, string loginID, out double issuedAt, out double expiryAt)
{
var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
expiryAt = Math.Round((DateTime.UtcNow.AddMinutes(TokenLifeDuration) - unixEpoch).TotalSeconds);
issuedAt = Math.Round((DateTime.UtcNow - unixEpoch).TotalSeconds);
var payload = new Dictionary<string, object>
{
{enmUserIdentity.UserName.ToString(), user.Name},
{enmUserIdentity.EmailID.ToString(), user.Email},
{enmUserIdentity.UserID.ToString(), user.UserID},
{enmUserIdentity.LoginID.ToString(), loginID}
,{"iat", issuedAt}
,{"exp", expiryAt}
};
var secret = "w$e$#*az";
var token = JsonWebToken.Encode(payload, secret, JwtHashAlgorithm.HS256);
return token;
}
public static int TokenLifeDuration
{
get
{
int tokenLifeDuration = 20; // in minuets
return tokenLifeDuration;
}
}
internal static string CreateMasterToken(int userID, string loginID)
{
var payload = new Dictionary<string, object>
{
{enmUserIdentity.LoginID.ToString(), loginID},
{enmUserIdentity.UserID.ToString(), userID},
{"instanceid", DateTime.Now.ToFileTime()}
};
var secret = "w$e$#*az";
var token = JsonWebToken.Encode(payload, secret, JwtHashAlgorithm.HS256);
return token;
}
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.MessageHandlers.Add(new AuthHandler());
}
}
令牌控制器.cs
public class TokenController : ApiController
{
[AllowAnonymous]
[Route("signin")]
[HttpPost]
public HttpResponseMessage Login(Login model)
{
HttpResponseMessage response = null;
DataTable dtblLogin = null;
double issuedAt;
double expiryAt;
if (ModelState.IsValid)
{
dtblLogin = LoginManager.GetUserLoginDetails(model.LoginID, model.Password, true);
if (dtblLogin == null || dtblLogin.Rows.Count == 0)
{
response = Request.CreateResponse(HttpStatusCode.NotFound);
}
else
{
User loggedInUser = new User();
loggedInUser.UserID = Convert.ToInt32(dtblLogin.Rows[0]["UserID"]);
loggedInUser.Email = Convert.ToString(dtblLogin.Rows[0]["UserEmailID"]);
loggedInUser.Name = Convert.ToString(dtblLogin.Rows[0]["LastName"]) + " " + Convert.ToString(dtblLogin.Rows[0]["FirstName"]);
string token = AuthFactory.CreateToken(loggedInUser, model.LoginID, out issuedAt, out expiryAt);
loggedInUser.Token = token;
response = Request.CreateResponse(loggedInUser);
}
}
else
{
response = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
return response;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
PremiumCalculatorController.cs
PremiumCalculatorController : ApiController
{
[HttpPost]
public IHttpActionResult CalculatAnnualPremium(PremiumFactorInfo premiumFactDetails)
{
PremiumInfo result;
result = AnnualPremium.GetPremium(premiumFactDetails);
return Ok(result);
}
}
Web 表单申请
Login.aspx.cs
public class Login
{
protected void imgbtnLogin_Click(object sender, System.EventArgs s)
{
UserInfo loggedinUser = LoginManager.ValidateUser(txtUserID.text.trim(), txtPassword.text);
if (loggedinUser != null)
{
byte[] password = LoginManager.EncryptPassword(txtPassword.text);
APIToken tokenInfo = ApiLoginManager.Login(txtUserID.text.trim(), password);
loggedinUser.AccessToken = tokenInfo.Token;
Session.Add("LoggedInUser", loggedinUser);
Response.Redirect("Home.aspx");
}
else
{
msg.Show("Logn ID or Password is invalid.");
}
}
}
ApiLoginManager.cs
public class ApiLoginManager
{
public UserDetails Login(string userName, byte[] password)
{
APIToken result = null;
UserLogin objLoginInfo;
string webAPIBaseURL = "http://localhost/polwebapiService/"
try
{
using (var client = new HttpClient())
{
result = new UserDetails();
client.BaseAddress = new Uri(webAPIBaseURL);
objLoginInfo = new UserLogin { LoginID = userName, Password = password };
var response = client.PostAsJsonAsync("api/token/Login", objLoginInfo);
if (response.Result.IsSuccessStatusCode)
{
string jsonResponce = response.Result.Content.ReadAsStringAsync().Result;
result = JsonConvert.DeserializeObject<APIToken>(jsonResponce);
}
response = null;
}
return result;
}
catch (Exception ex)
{
throw ex;
}
}
}
AnnualPremiumCalculator.aspx.cs
public class AnnualPremiumCalculator
{
protected void imgbtnCalculatePremium_Click(object sender, System.EventArgs s)
{
string token = ((UserInfo)Session["LoggedInUser"]).AccessToken;
PremiumFactors premiumFacts = CollectUserInputPremiumFactors();
PremiumInfo premiumDet = CalculatePremium(premiumFacts, token);
txtAnnulPremium.text = premiumDet.Premium;
//other details so on
}
public PremiumInfo CalculatePremium(PremiumFactors premiumFacts, string accessToken)
{
PremiumInfo result = null;
string webAPIBaseURL = "http://localhost/polwebapiService/";
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(webAPIBaseURL);
StringContent content = new StringContent(JsonConvert.SerializeObject(premiumFacts), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = client.PostAsync("api/calculators/PremiumCalculator", content);
if (response.Result.IsSuccessStatusCode)
{
string jsonResponce = response.Result.Content.ReadAsStringAsync().Result;
result = JsonConvert.DeserializeObject<PremiumInfo>(jsonResponce);
}
response = null;
}
return result;
}
finally
{
}
}
}
以上是说明问题的示例代码,可能有一些错字。
这可以通过单独的持久刷新令牌来完成。 http://www.c-sharpcorner.com/article/handle-refresh-token-using-asp-net-core-2-0-and-json-web-token/
上的精彩教程
我有几点要说:
访问令牌应由客户端保存,而不是在服务器的会话中。刷新令牌也是如此。原因是,通常没有会话。智能客户端可以在没有会话的情况下处理令牌,MVC 网站可以使用 cookie 而 API 不知道会话。这不是禁止的,但是你又需要担心会话过期,当你重启服务器时所有用户都必须重新登录。
如果您想实施 OAuth,请阅读 specification。在那里你会找到实现刷新令牌所需的一切。
您在 TokenController 中处理登录。在那里你也应该检查 other conditions。
- grant_type = 密码
- 内容类型必须是“application/x-www-form-urlencoded”
- 只有通过安全线路 (https) 发送的请求才会得到处理。
当获取access_token时,只有在请求refresh_token时,才应该在access_token中包含refresh_token。
您不需要 client applications (grant_type = client_credentials) 的刷新令牌,因为它们使用 clientid / secret 来获取访问令牌。扩展 TokenController 以允许 client_credentials 流。请注意:刷新令牌仅供 用户 使用,并且只有在可以保密的情况下才应使用。刷新令牌非常强大,请小心处理。
为了refresh an access token,您需要将刷新令牌发送到端点。在您的情况下,您可以扩展 TokenController 以允许 refresh_token 请求。您需要检查:
- grant_type = refresh_token
- 内容类型必须是“application/x-www-form-urlencoded”
- 刷新令牌有多种场景,您也可以组合使用:
- 将刷新令牌保存在数据库中。每次使用刷新令牌时,您都可以将其从数据库中删除,然后保存新的刷新令牌,该刷新令牌也会在新的 access_token.
中返回
- 将刷新令牌设置为更长的生命周期,并且在刷新访问令牌时不刷新它。在这种情况下,返回的 access_token 不包含新的刷新令牌。这样您就需要在 refresh_token 到期后重新登录。
请注意,永不过期且无法撤销的刷新令牌为用户提供了无限制的访问权限,因此请谨慎实施。
在我的回答中here您可以看到如何使用身份 2 处理刷新令牌。您可以考虑切换到身份 2。
我想我已经提到了一切。如果我遗漏了什么或不清楚的地方,请告诉我。
我在 web API 实现方面相当陌生,我创建了一个 web API 服务以将其与 ASP.net web form
应用程序以及一些独立应用程序一起使用(C# Console/Windows 应用程序)使用 HttpClient
object.
我已经在 web api 中实现了一个具有过期时间限制的基本 JWT 访问令牌身份验证,这种身份验证技术在令牌未过期之前工作正常,当令牌过期时 web api 不接受作为令牌的请求已过期!根据身份验证实现,这很好,但我想在 web api 中实现刷新令牌逻辑,因此令牌可以 renew/refersh 并且客户端应该能够使用 web api 资源。
我在谷歌上搜索了很多但无法找到刷新令牌逻辑的正确实现。如果有人有正确的方法来处理过期的访问令牌,请帮助我。
以下是我在 asp.net 应用程序中使用网络 api 所遵循的步骤。
在 ASP.net web 表单登录页面我调用了 web API "TokenController" 这个控制器有两个参数 loginID 和 password 以及 return JWT我存储在 session object 中的令牌。
现在,每当我的客户端应用程序也需要使用 Web api 资源时,在调用 Web api 时,资源必须在请求 header 中发送访问令牌
httpclient
.但是当令牌过期时,客户端无法使用网络 api 资源,他必须重新登录并更新令牌!这是我不想要的,用户不应提示再次登录,因为应用程序 session 超时尚未结束。
如何在不强制用户重新登录的情况下刷新令牌。
如果我下面给出的 JWT 访问令牌实现逻辑不合适或者不正确,请告诉我正确的方法。
代码如下
WebAPI
AuthHandler.cs
public class AuthHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage errorResponse = null;
try
{
IEnumerable<string> authHeaderValues;
request.Headers.TryGetValues("Authorization", out authHeaderValues);
if (authHeaderValues == null)
return base.SendAsync(request, cancellationToken);
var requestToken = authHeaderValues.ElementAt(0);
var token = "";
if (requestToken.StartsWith("Bearer ", StringComparison.CurrentCultureIgnoreCase))
{
token = requestToken.Substring("Bearer ".Length);
}
var secret = "w$e$#*az";
ClaimsPrincipal cp = ValidateToken(token, secret, true);
Thread.CurrentPrincipal = cp;
if (HttpContext.Current != null)
{
Thread.CurrentPrincipal = cp;
HttpContext.Current.User = cp;
}
}
catch (SignatureVerificationException ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex.Message);
}
catch (Exception ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
}
return errorResponse != null
? Task.FromResult(errorResponse)
: base.SendAsync(request, cancellationToken);
}
private static ClaimsPrincipal ValidateToken(string token, string secret, bool checkExpiration)
{
var jsonSerializer = new JavaScriptSerializer();
string payloadJson = string.Empty;
try
{
payloadJson = JsonWebToken.Decode(token, secret);
}
catch (Exception)
{
throw new SignatureVerificationException("Unauthorized access!");
}
var payloadData = jsonSerializer.Deserialize<Dictionary<string, object>>(payloadJson);
object exp;
if (payloadData != null && (checkExpiration && payloadData.TryGetValue("exp", out exp)))
{
var validTo = AuthFactory.FromUnixTime(long.Parse(exp.ToString()));
if (DateTime.Compare(validTo, DateTime.UtcNow) <= 0)
{
throw new SignatureVerificationException("Token is expired!");
}
}
var clmsIdentity = new ClaimsIdentity("Federation", ClaimTypes.Name, ClaimTypes.Role);
var claims = new List<Claim>();
if (payloadData != null)
foreach (var pair in payloadData)
{
var claimType = pair.Key;
var source = pair.Value as ArrayList;
if (source != null)
{
claims.AddRange(from object item in source
select new Claim(claimType, item.ToString(), ClaimValueTypes.String));
continue;
}
switch (pair.Key.ToUpper())
{
case "USERNAME":
claims.Add(new Claim(ClaimTypes.Name, pair.Value.ToString(), ClaimValueTypes.String));
break;
case "EMAILID":
claims.Add(new Claim(ClaimTypes.Email, pair.Value.ToString(), ClaimValueTypes.Email));
break;
case "USERID":
claims.Add(new Claim(ClaimTypes.UserData, pair.Value.ToString(), ClaimValueTypes.Integer));
break;
default:
claims.Add(new Claim(claimType, pair.Value.ToString(), ClaimValueTypes.String));
break;
}
}
clmsIdentity.AddClaims(claims);
ClaimsPrincipal cp = new ClaimsPrincipal(clmsIdentity);
return cp;
}
}
AuthFactory.cs
public static class AuthFactory
{
internal static DateTime FromUnixTime(double unixTime)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddSeconds(unixTime);
}
internal static string CreateToken(User user, string loginID, out double issuedAt, out double expiryAt)
{
var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
expiryAt = Math.Round((DateTime.UtcNow.AddMinutes(TokenLifeDuration) - unixEpoch).TotalSeconds);
issuedAt = Math.Round((DateTime.UtcNow - unixEpoch).TotalSeconds);
var payload = new Dictionary<string, object>
{
{enmUserIdentity.UserName.ToString(), user.Name},
{enmUserIdentity.EmailID.ToString(), user.Email},
{enmUserIdentity.UserID.ToString(), user.UserID},
{enmUserIdentity.LoginID.ToString(), loginID}
,{"iat", issuedAt}
,{"exp", expiryAt}
};
var secret = "w$e$#*az";
var token = JsonWebToken.Encode(payload, secret, JwtHashAlgorithm.HS256);
return token;
}
public static int TokenLifeDuration
{
get
{
int tokenLifeDuration = 20; // in minuets
return tokenLifeDuration;
}
}
internal static string CreateMasterToken(int userID, string loginID)
{
var payload = new Dictionary<string, object>
{
{enmUserIdentity.LoginID.ToString(), loginID},
{enmUserIdentity.UserID.ToString(), userID},
{"instanceid", DateTime.Now.ToFileTime()}
};
var secret = "w$e$#*az";
var token = JsonWebToken.Encode(payload, secret, JwtHashAlgorithm.HS256);
return token;
}
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.MessageHandlers.Add(new AuthHandler());
}
}
令牌控制器.cs
public class TokenController : ApiController
{
[AllowAnonymous]
[Route("signin")]
[HttpPost]
public HttpResponseMessage Login(Login model)
{
HttpResponseMessage response = null;
DataTable dtblLogin = null;
double issuedAt;
double expiryAt;
if (ModelState.IsValid)
{
dtblLogin = LoginManager.GetUserLoginDetails(model.LoginID, model.Password, true);
if (dtblLogin == null || dtblLogin.Rows.Count == 0)
{
response = Request.CreateResponse(HttpStatusCode.NotFound);
}
else
{
User loggedInUser = new User();
loggedInUser.UserID = Convert.ToInt32(dtblLogin.Rows[0]["UserID"]);
loggedInUser.Email = Convert.ToString(dtblLogin.Rows[0]["UserEmailID"]);
loggedInUser.Name = Convert.ToString(dtblLogin.Rows[0]["LastName"]) + " " + Convert.ToString(dtblLogin.Rows[0]["FirstName"]);
string token = AuthFactory.CreateToken(loggedInUser, model.LoginID, out issuedAt, out expiryAt);
loggedInUser.Token = token;
response = Request.CreateResponse(loggedInUser);
}
}
else
{
response = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
return response;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
PremiumCalculatorController.cs
PremiumCalculatorController : ApiController
{
[HttpPost]
public IHttpActionResult CalculatAnnualPremium(PremiumFactorInfo premiumFactDetails)
{
PremiumInfo result;
result = AnnualPremium.GetPremium(premiumFactDetails);
return Ok(result);
}
}
Web 表单申请
Login.aspx.cs
public class Login
{
protected void imgbtnLogin_Click(object sender, System.EventArgs s)
{
UserInfo loggedinUser = LoginManager.ValidateUser(txtUserID.text.trim(), txtPassword.text);
if (loggedinUser != null)
{
byte[] password = LoginManager.EncryptPassword(txtPassword.text);
APIToken tokenInfo = ApiLoginManager.Login(txtUserID.text.trim(), password);
loggedinUser.AccessToken = tokenInfo.Token;
Session.Add("LoggedInUser", loggedinUser);
Response.Redirect("Home.aspx");
}
else
{
msg.Show("Logn ID or Password is invalid.");
}
}
}
ApiLoginManager.cs
public class ApiLoginManager
{
public UserDetails Login(string userName, byte[] password)
{
APIToken result = null;
UserLogin objLoginInfo;
string webAPIBaseURL = "http://localhost/polwebapiService/"
try
{
using (var client = new HttpClient())
{
result = new UserDetails();
client.BaseAddress = new Uri(webAPIBaseURL);
objLoginInfo = new UserLogin { LoginID = userName, Password = password };
var response = client.PostAsJsonAsync("api/token/Login", objLoginInfo);
if (response.Result.IsSuccessStatusCode)
{
string jsonResponce = response.Result.Content.ReadAsStringAsync().Result;
result = JsonConvert.DeserializeObject<APIToken>(jsonResponce);
}
response = null;
}
return result;
}
catch (Exception ex)
{
throw ex;
}
}
}
AnnualPremiumCalculator.aspx.cs
public class AnnualPremiumCalculator
{
protected void imgbtnCalculatePremium_Click(object sender, System.EventArgs s)
{
string token = ((UserInfo)Session["LoggedInUser"]).AccessToken;
PremiumFactors premiumFacts = CollectUserInputPremiumFactors();
PremiumInfo premiumDet = CalculatePremium(premiumFacts, token);
txtAnnulPremium.text = premiumDet.Premium;
//other details so on
}
public PremiumInfo CalculatePremium(PremiumFactors premiumFacts, string accessToken)
{
PremiumInfo result = null;
string webAPIBaseURL = "http://localhost/polwebapiService/";
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(webAPIBaseURL);
StringContent content = new StringContent(JsonConvert.SerializeObject(premiumFacts), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = client.PostAsync("api/calculators/PremiumCalculator", content);
if (response.Result.IsSuccessStatusCode)
{
string jsonResponce = response.Result.Content.ReadAsStringAsync().Result;
result = JsonConvert.DeserializeObject<PremiumInfo>(jsonResponce);
}
response = null;
}
return result;
}
finally
{
}
}
}
以上是说明问题的示例代码,可能有一些错字。
这可以通过单独的持久刷新令牌来完成。 http://www.c-sharpcorner.com/article/handle-refresh-token-using-asp-net-core-2-0-and-json-web-token/
上的精彩教程我有几点要说:
访问令牌应由客户端保存,而不是在服务器的会话中。刷新令牌也是如此。原因是,通常没有会话。智能客户端可以在没有会话的情况下处理令牌,MVC 网站可以使用 cookie 而 API 不知道会话。这不是禁止的,但是你又需要担心会话过期,当你重启服务器时所有用户都必须重新登录。
如果您想实施 OAuth,请阅读 specification。在那里你会找到实现刷新令牌所需的一切。
您在 TokenController 中处理登录。在那里你也应该检查 other conditions。
- grant_type = 密码
- 内容类型必须是“application/x-www-form-urlencoded”
- 只有通过安全线路 (https) 发送的请求才会得到处理。
当获取access_token时,只有在请求refresh_token时,才应该在access_token中包含refresh_token。
您不需要 client applications (grant_type = client_credentials) 的刷新令牌,因为它们使用 clientid / secret 来获取访问令牌。扩展 TokenController 以允许 client_credentials 流。请注意:刷新令牌仅供 用户 使用,并且只有在可以保密的情况下才应使用。刷新令牌非常强大,请小心处理。
为了refresh an access token,您需要将刷新令牌发送到端点。在您的情况下,您可以扩展 TokenController 以允许 refresh_token 请求。您需要检查:
- grant_type = refresh_token
- 内容类型必须是“application/x-www-form-urlencoded”
- 刷新令牌有多种场景,您也可以组合使用:
- 将刷新令牌保存在数据库中。每次使用刷新令牌时,您都可以将其从数据库中删除,然后保存新的刷新令牌,该刷新令牌也会在新的 access_token. 中返回
- 将刷新令牌设置为更长的生命周期,并且在刷新访问令牌时不刷新它。在这种情况下,返回的 access_token 不包含新的刷新令牌。这样您就需要在 refresh_token 到期后重新登录。
请注意,永不过期且无法撤销的刷新令牌为用户提供了无限制的访问权限,因此请谨慎实施。
在我的回答中here您可以看到如何使用身份 2 处理刷新令牌。您可以考虑切换到身份 2。
我想我已经提到了一切。如果我遗漏了什么或不清楚的地方,请告诉我。