ServiceStack 6 CredentialsAuthProvider 没有 return BearerToken
ServiceStack 6 CredentialsAuthProvider does not return BearerToken
我们的商店多年来一直在使用 ServiceStack 库,没有出现过很多问题。
最近,从5.12版本升级到6.0版本后,我们看到一个基于凭证的认证请求没有返回BearerToken。
我已阅读有关 JWT 更改的发行说明部分,here, and I understand the "breaking" change, as well as here,其中描述了如何恢复为在响应中返回不记名令牌。但是,建议的更改是针对 JwtAuthProvider,而不是 CredentialsAuthProvider。 CredentialsAuthProvider 没有 UseTokenCookie 属性.
当身份验证提供程序是 CredentialsAuthProvider 时,是否有办法恢复为在身份验证响应中返回不记名令牌?
关于它的价值,这里是相关的服务器代码:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
private readonly IDbContext _dbContext;
private const string AuthProviderType = "credentials";
public CustomCredentialsAuthProvider(IDbContext dbContext)
{
_dbContext = dbContext;
}
public override async Task<bool> TryAuthenticateAsync(IServiceBase authService,
string userName, string password, CancellationToken token=default)
{
var userAuthentication = _dbContext.GetUserAuthenticationData(userName);
return (userAuthentication != null && HashHelper.VerifyHash(password, userAuthentication.PasswordSalt, userAuthentication.PasswordHash));
}
public override async Task<IHttpResult> OnAuthenticatedAsync(IServiceBase authService,
IAuthSession session, IAuthTokens tokens,
Dictionary<string, string> authInfo, CancellationToken token=default)
{
var customUserSession = (CustomUserSession)session;
var userId = _dbContext.GetUserId(string.Empty, customUserSession.UserAuthName);
if (!userId.HasValue) throw new AuthenticationException("Unable to locate UserId");
var claims = _dbContext.GetClaims(userId.Value);
var postalCode = _dbContext.GetPostalCode(userId.Value);
HydrateCustomUserSession(claims.ToList(), customUserSession, postalCode);
//Call base method to Save Session and fire Auth/Session callbacks:
return result = await base.OnAuthenticatedAsync(authService, customUserSession, tokens, authInfo, token);
}
private void HydrateCustomUserSession(IReadOnlyCollection<Claims> claims, CustomUserSession customUserSession, string postalCode)
{
customUserSession.AuthProvider = AuthProviderType;
customUserSession.CreatedAt = DateTime.UtcNow;
customUserSession.UserId = Convert.ToInt32(claims.First(item => item.ClaimName == "sub").ClaimValue);
customUserSession.UserStatusId = Convert.ToInt32(claims.First(item => item.ClaimName == "user_status_id").ClaimValue);
customUserSession.UserAuthId = claims.First(item => item.ClaimName == "sub").ClaimValue;
customUserSession.FirstName = claims.First(item => item.ClaimName == "given_name").ClaimValue;
customUserSession.LastName = claims.First(item => item.ClaimName == "family_name").ClaimValue;
customUserSession.Email = claims.First(item => item.ClaimName == "email").ClaimValue;
customUserSession.Company = claims.First(item => item.ClaimName == "company_name").ClaimValue;
customUserSession.CompanyId = Convert.ToInt32(claims.First(item => item.ClaimName == "company_id").ClaimValue);
customUserSession.CompanyTypeId = Convert.ToInt32(claims.First(item => item.ClaimName == "company_type_id").ClaimValue);
customUserSession.PostalCode = postalCode;
var productIds = claims.First(item => item.ClaimName == "product_ids").ClaimValue;
if (!string.IsNullOrEmpty(productIds))
{
customUserSession.ProductIds = productIds.Split(",").Select(int.Parse).ToList();
}
else
{
customUserSession.ProductIds = new List<int>();
}
var productFeatureIds = claims.First(item => item.ClaimName == "product_feature_ids").ClaimValue;
if (!string.IsNullOrEmpty(productFeatureIds))
{
customUserSession.ProductFeatureIds = productFeatureIds.Split(",").Select(int.Parse).ToList();
}
else
{
customUserSession.ProductFeatureIds = new List<int>();
}
var userRoles = claims.First(item => item.ClaimName == "user_roles").ClaimValue;
if (!string.IsNullOrEmpty(userRoles))
{
customUserSession.UserRoles = userRoles.Split(",").Select(x => new UserRole(x)).ToList();
}
else
{
customUserSession.UserRoles = new List<UserRole>();
}
}
}
在客户端,这是一个批处理驱动的处理器,而不是网络应用程序。身份验证部分在这里:
private static void GetBearerToken()
{
var authRequest = new Authenticate()
{
UserName = ConfigHelper.ServiceUserName,
Password = ConfigHelper.ServicePassword,
provider = "credentials",
RememberMe = true
};
var authResponse = _authServiceClient.Post(authRequest);
// BearerToken was returned until the auth service was updated to using ServiceStack 6.0
// After using 6.0, BearerToken is empty.
_myOtherServiceClient.BearerToken = authResponse.BearerToken;
}
填充后,不记名令牌用于验证对其他服务的调用。
感谢您的帮助!
如果您使用的是 JWT,您将在 AuthFeature
插件中配置 JwtAuthProvider
,这是需要使用 UseTokenCookie=false
配置的 JWT 令牌在响应 DTO 上填充(即,而不是使用令牌 Cookie),如 explained in the linked docs.
new JwtAuthProvider(AppSettings) {
UseTokenCookie = false
}
虽然您应该考虑使用推荐的 JWT 令牌 cookie,因为成功的身份验证仍然会导致经过身份验证的 _authServiceClient
:
var authResponse = _authServiceClient.Post(authRequest);
// manual JWT handling is unnecessary when using Token Cookies
//_myOtherServiceClient.BearerToken = authResponse.BearerToken;
由于 JWT 令牌是在 HTTP Cookie 中返回的,这将节省手动 handling/populating 承载令牌所需的额外工作,包括服务器 auto-refreshing 在 v6.[=17 中过期的 JWT 承载令牌=]
我们的商店多年来一直在使用 ServiceStack 库,没有出现过很多问题。 最近,从5.12版本升级到6.0版本后,我们看到一个基于凭证的认证请求没有返回BearerToken。
我已阅读有关 JWT 更改的发行说明部分,here, and I understand the "breaking" change, as well as here,其中描述了如何恢复为在响应中返回不记名令牌。但是,建议的更改是针对 JwtAuthProvider,而不是 CredentialsAuthProvider。 CredentialsAuthProvider 没有 UseTokenCookie 属性.
当身份验证提供程序是 CredentialsAuthProvider 时,是否有办法恢复为在身份验证响应中返回不记名令牌?
关于它的价值,这里是相关的服务器代码:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
private readonly IDbContext _dbContext;
private const string AuthProviderType = "credentials";
public CustomCredentialsAuthProvider(IDbContext dbContext)
{
_dbContext = dbContext;
}
public override async Task<bool> TryAuthenticateAsync(IServiceBase authService,
string userName, string password, CancellationToken token=default)
{
var userAuthentication = _dbContext.GetUserAuthenticationData(userName);
return (userAuthentication != null && HashHelper.VerifyHash(password, userAuthentication.PasswordSalt, userAuthentication.PasswordHash));
}
public override async Task<IHttpResult> OnAuthenticatedAsync(IServiceBase authService,
IAuthSession session, IAuthTokens tokens,
Dictionary<string, string> authInfo, CancellationToken token=default)
{
var customUserSession = (CustomUserSession)session;
var userId = _dbContext.GetUserId(string.Empty, customUserSession.UserAuthName);
if (!userId.HasValue) throw new AuthenticationException("Unable to locate UserId");
var claims = _dbContext.GetClaims(userId.Value);
var postalCode = _dbContext.GetPostalCode(userId.Value);
HydrateCustomUserSession(claims.ToList(), customUserSession, postalCode);
//Call base method to Save Session and fire Auth/Session callbacks:
return result = await base.OnAuthenticatedAsync(authService, customUserSession, tokens, authInfo, token);
}
private void HydrateCustomUserSession(IReadOnlyCollection<Claims> claims, CustomUserSession customUserSession, string postalCode)
{
customUserSession.AuthProvider = AuthProviderType;
customUserSession.CreatedAt = DateTime.UtcNow;
customUserSession.UserId = Convert.ToInt32(claims.First(item => item.ClaimName == "sub").ClaimValue);
customUserSession.UserStatusId = Convert.ToInt32(claims.First(item => item.ClaimName == "user_status_id").ClaimValue);
customUserSession.UserAuthId = claims.First(item => item.ClaimName == "sub").ClaimValue;
customUserSession.FirstName = claims.First(item => item.ClaimName == "given_name").ClaimValue;
customUserSession.LastName = claims.First(item => item.ClaimName == "family_name").ClaimValue;
customUserSession.Email = claims.First(item => item.ClaimName == "email").ClaimValue;
customUserSession.Company = claims.First(item => item.ClaimName == "company_name").ClaimValue;
customUserSession.CompanyId = Convert.ToInt32(claims.First(item => item.ClaimName == "company_id").ClaimValue);
customUserSession.CompanyTypeId = Convert.ToInt32(claims.First(item => item.ClaimName == "company_type_id").ClaimValue);
customUserSession.PostalCode = postalCode;
var productIds = claims.First(item => item.ClaimName == "product_ids").ClaimValue;
if (!string.IsNullOrEmpty(productIds))
{
customUserSession.ProductIds = productIds.Split(",").Select(int.Parse).ToList();
}
else
{
customUserSession.ProductIds = new List<int>();
}
var productFeatureIds = claims.First(item => item.ClaimName == "product_feature_ids").ClaimValue;
if (!string.IsNullOrEmpty(productFeatureIds))
{
customUserSession.ProductFeatureIds = productFeatureIds.Split(",").Select(int.Parse).ToList();
}
else
{
customUserSession.ProductFeatureIds = new List<int>();
}
var userRoles = claims.First(item => item.ClaimName == "user_roles").ClaimValue;
if (!string.IsNullOrEmpty(userRoles))
{
customUserSession.UserRoles = userRoles.Split(",").Select(x => new UserRole(x)).ToList();
}
else
{
customUserSession.UserRoles = new List<UserRole>();
}
}
}
在客户端,这是一个批处理驱动的处理器,而不是网络应用程序。身份验证部分在这里:
private static void GetBearerToken()
{
var authRequest = new Authenticate()
{
UserName = ConfigHelper.ServiceUserName,
Password = ConfigHelper.ServicePassword,
provider = "credentials",
RememberMe = true
};
var authResponse = _authServiceClient.Post(authRequest);
// BearerToken was returned until the auth service was updated to using ServiceStack 6.0
// After using 6.0, BearerToken is empty.
_myOtherServiceClient.BearerToken = authResponse.BearerToken;
}
填充后,不记名令牌用于验证对其他服务的调用。 感谢您的帮助!
如果您使用的是 JWT,您将在 AuthFeature
插件中配置 JwtAuthProvider
,这是需要使用 UseTokenCookie=false
配置的 JWT 令牌在响应 DTO 上填充(即,而不是使用令牌 Cookie),如 explained in the linked docs.
new JwtAuthProvider(AppSettings) {
UseTokenCookie = false
}
虽然您应该考虑使用推荐的 JWT 令牌 cookie,因为成功的身份验证仍然会导致经过身份验证的 _authServiceClient
:
var authResponse = _authServiceClient.Post(authRequest);
// manual JWT handling is unnecessary when using Token Cookies
//_myOtherServiceClient.BearerToken = authResponse.BearerToken;
由于 JWT 令牌是在 HTTP Cookie 中返回的,这将节省手动 handling/populating 承载令牌所需的额外工作,包括服务器 auto-refreshing 在 v6.[=17 中过期的 JWT 承载令牌=]