tl; dr
使用IdentityServer3作为身份验证服务器,如何在ASP.NET MVC项目(表格,jQuery,Axios(中发布数据。另外,要使用什么流程来进行此工作?
我经历的
我有一个工作的IdentityServer3实例。我也有一个ASP.NET MVC项目。使用混合流,因为我将不得不将用户的令牌传递给其他服务。身份验证本身有效 - 当页面仅使用get时。即使身份验证的用户令牌已过期,后台也将请求重定向到AUTH。服务器,用户可以继续其工作,而无需要求用户再次登录。(据我了解,混合流可以使用刷新令牌,因此我认为这就是它可以重新认证用户的方式。即使HttpContext.Current.User.Identity.IsAuthenticated=false
(
出于测试目的,我将AccessTokenLifetime
,AuthorizationCodeLifetime
和IdentityTokenLifetime
值设置为auth中的5秒。服务器。据我所知,刷新令牌的到期时间是在几天内测得的,我没有更改默认值。
但是当我尝试使用帖子时,事情变得"丑陋"。
- 使用表单帖子,带有已过期的令牌,请求将重定向到IdentityServer3。它确实是魔术(用户被身份验证(并将重定向到我的页面 - 作为获取请求...我在URL中看到了
response_mode=form_post
,但已发布的有效载荷消失了。 - 使用Axios Post,请求将请求重定向到IdentityServer3,但在飞行前选项请求中失败。
- 使用默认的jQuery帖子,有同样的错误。(即使默认的jQuery帖子使用
application/x-www-form-urlencoded
来解决飞行前问题。(
startup.cs
const string authType = "Cookies";
// resetting Microsoft's default mapper
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
// ensure, that the MVC anti forgery key engine will use our "custom" user id
AntiForgeryConfig.UniqueClaimTypeIdentifier = "sub";
app.UseCookieAuthentication(new Microsoft.Owin.Security.Cookies.CookieAuthenticationOptions
{
AuthenticationType = authType
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
RedirectUri = adminUri,
PostLogoutRedirectUri = adminUri,
Authority = idServerIdentityEndpoint,
SignInAsAuthenticationType = authType,
ResponseType = "code id_token",
Scope = "openid profile roles email offline_access",
Notifications = new OpenIdConnectAuthenticationNotifications
{
#region Handle automatic redirect (on logout)
RedirectToIdentityProvider = async n =>
{
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType ==
OpenIdConnectRequestType.LogoutRequest)
{
var token = n.OwinContext.Authentication.User.FindFirst(idTokenName);
if (token != null)
{
var idTokenHint =
token.Value;
n.ProtocolMessage.IdTokenHint = idTokenHint;
}
}
},
#endregion
AuthorizationCodeReceived = async n =>
{
System.Diagnostics.Debug.Print("AuthorizationCodeReceived " + n.ProtocolMessage.ToString());
// fetch the identity from authentication response
var identity = n.AuthenticationTicket.Identity;
// exchange the "code" token for access_token, id_token, refresh_token, using the client secret
var requestResponse = await OidcClient.CallTokenEndpointAsync(
new Uri(idServerTokenEndpoint),
new Uri(adminUri),
n.Code,
clientId,
clientSecret
);
// fetch tokens from the exchange response
identity.AddClaims(new []
{
new Claim("access_token", requestResponse.AccessToken),
new Claim("id_token", requestResponse.IdentityToken),
new Claim("refresh_token", requestResponse.RefreshToken)
});
// store the refresh_token in the session, as the user might be logged out, when the authorization attribute is executed
// see OrganicaAuthorize.cs
HttpContext.Current.Session["refresh_token"] = requestResponse.RefreshToken;
// get the userinfo from the openId endpoint
// this actually retreives all the claims, but using the normal access token
var userInfo = await EndpointAndTokenHelper.CallUserInfoEndpoint(idServerUserInfoEndpoint, requestResponse.AccessToken); // todo: userinfo
if (userInfo == null) throw new Exception("Could not retreive user information from identity server.");
#region Extract individual claims
// extract claims we are interested in
var nameClaim = new Claim(Thinktecture.IdentityModel.Client.JwtClaimTypes.Name,
userInfo.Value<string>(Thinktecture.IdentityModel.Client.JwtClaimTypes.Name)); // full name
var givenNameClaim = new Claim(Thinktecture.IdentityModel.Client.JwtClaimTypes.GivenName,
userInfo.Value<string>(Thinktecture.IdentityModel.Client.JwtClaimTypes.GivenName)); // given name
var familyNameClaim = new Claim(Thinktecture.IdentityModel.Client.JwtClaimTypes.FamilyName,
userInfo.Value<string>(Thinktecture.IdentityModel.Client.JwtClaimTypes.FamilyName)); // family name
var emailClaim = new Claim(Thinktecture.IdentityModel.Client.JwtClaimTypes.Email,
userInfo.Value<string>(Thinktecture.IdentityModel.Client.JwtClaimTypes.Email)); // email
var subClaim = new Claim(Thinktecture.IdentityModel.Client.JwtClaimTypes.Subject,
userInfo.Value<string>(Thinktecture.IdentityModel.Client.JwtClaimTypes.Subject)); // userid
#endregion
#region Extract roles
List<string> roles;
try
{
roles = userInfo.Value<JArray>(Thinktecture.IdentityModel.Client.JwtClaimTypes.Role).Select(r => r.ToString()).ToList();
}
catch (InvalidCastException) // if there is only 1 item
{
roles = new List<string> { userInfo.Value<string>(Thinktecture.IdentityModel.Client.JwtClaimTypes.Role) };
}
#endregion
// attach the claims we just extracted
identity.AddClaims(new[] { nameClaim, givenNameClaim, familyNameClaim, subClaim, emailClaim });
// attach roles
identity.AddClaims(roles.Select(r => new Claim(Thinktecture.IdentityModel.Client.JwtClaimTypes.Role, r.ToString())));
// update the return value of the SecurityTokenValidated method (this method...)
n.AuthenticationTicket = new AuthenticationTicket(
identity,
n.AuthenticationTicket.Properties);
},
AuthenticationFailed = async n =>
{
System.Diagnostics.Debug.Print("AuthenticationFailed " + n.Exception.ToString());
},
MessageReceived = async n =>
{
System.Diagnostics.Debug.Print("MessageReceived " + n.State.ToString());
},
SecurityTokenReceived = async n =>
{
System.Diagnostics.Debug.Print("SecurityTokenReceived " + n.State.ToString());
},
SecurityTokenValidated = async n =>
{
System.Diagnostics.Debug.Print("SecurityTokenValidated " + n.State.ToString());
}
}
});
您是否在MVC应用中配置了Cookie Authentication Mudindware?使用身份服务器进行身份验证后,应设置身份验证cookie。设置身份验证cookie并在cookie到期/删除之前不会发生有效的身份服务器重定向。
更新1:
好吧,我误解了问题。会话时间淘汰时,重定向到身份服务器是合乎逻辑的。它无法与后有效载荷一起使用。您可以尝试执行以下操作。
- 如果请求是普通帖子,请再次将用户重定向到表单填写页面。
- 如果请求是AJAX帖子,请返回未经授权的结果,并基于该响应从JavaScript刷新页面。
无论如何,我认为除非您为此设计自己的解决方案,否则您将无法保留发布的数据。(例如,在本地存储数据(。
但是,如果您谨慎地确定身份服务器的会话超时和应用程序的会话超时,您可能会完全避免这种情况。
在OpenIdConnectAuthenticationOptions
设置UseTokenLifetime = false
中,它将打破身份令牌的寿命和cookie session Lifetime之间的连接。
在CookieAuthenticationOptions
中进行滑动到期
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(50),
现在,您是应用程序会话生命周期的不对制。调整它以符合您的需求和安全性。