/// <summary> /// BlackSignInTokenAsync /// </summary> /// <param name="signInToken"></param> /// <returns></returns> private async Task BlackSignInTokenAsync(SignInToken signInToken, string lastUser) { //TODO: 详细记录Black SiginInToken 的历史纪录 TransactionContext transactionContext = await _transaction.BeginTransactionAsync <SignInToken>().ConfigureAwait(false); try { await _signInTokenBiz.DeleteByGuidAsync(signInToken.Guid, lastUser, transactionContext).ConfigureAwait(false); await _transaction.CommitAsync(transactionContext).ConfigureAwait(false); } catch { await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false); throw; } }
/// <summary> /// ConstructJwtAsync /// </summary> /// <param name="user"></param> /// <param name="signInToken"></param> /// <param name="signToWhere"></param> /// <param name="transactionContext"></param> /// <returns></returns> /// <exception cref="DatabaseException"></exception> /// <exception cref="CacheException"></exception> private async Task <string> ConstructJwtAsync(User user, SignInToken signInToken, string?signToWhere, TransactionContext transactionContext) { IEnumerable <Role> roles = await _roleOfUserRepo.GetRolesByUserIdAsync(user.Id, transactionContext).ConfigureAwait(false); IEnumerable <UserClaim> userClaims = await _userClaimRepo.GetByUserIdAsync(user.Id, transactionContext).ConfigureAwait(false); IEnumerable <Claim> claims = ConstructClaims(user, roles, userClaims, signInToken); string jwt = JwtHelper.BuildJwt( claims, _options.OpenIdConnectConfiguration.Issuer, _options.NeedAudienceToBeChecked ? signToWhere : null, _options.SignInOptions.AccessTokenExpireTimeSpan, _signingCredentials, _encryptingCredentials); return(jwt); }
/// <summary> /// BlackSignInTokenAsync /// </summary> /// <param name="signInToken"></param> /// <returns></returns> /// <exception cref="DatabaseException"></exception> /// <exception cref="HB.Framework.Common.ValidateErrorException"></exception> private async Task BlackSignInTokenAsync(SignInToken signInToken) { //TODO: 详细记录Black SiginInToken 的历史纪录 TransactionContext transactionContext = await _database.BeginTransactionAsync <SignInToken>(IsolationLevel.ReadCommitted).ConfigureAwait(false); try { await _signInTokenBiz.DeleteAsync(signInToken.Guid, transactionContext).ConfigureAwait(false); await _database.CommitAsync(transactionContext).ConfigureAwait(false); } catch { await _database.RollbackAsync(transactionContext).ConfigureAwait(false); throw; } }
public static string BuildJwt( IEnumerable <Claim> claims, SignInToken signInToken, string issuer, string?audience, TimeSpan accessTokenExpiryTime, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials) { DateTime utcNow = DateTime.UtcNow; IList <Claim> claimList = claims.ToList(); claimList.Add(new Claim(ClaimExtensionTypes.SignInTokenGuid, signInToken.Guid)); //这个JWT只能在当前DeviceId上使用 claimList.Add(new Claim(ClaimExtensionTypes.DeviceId, signInToken.DeviceId)); JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); //JwtSecurityToken token = handler.CreateJwtSecurityToken( // _options.OpenIdConnectConfiguration.Issuer, // _options.NeedAudienceToBeChecked ? audience : null, // new ClaimsIdentity(claims), // utcNow, // utcNow + _signInOptions.AccessTokenExpireTimeSpan, // utcNow, // _signingCredentials, // _encryptingCredentials // ); JwtSecurityToken token = handler.CreateJwtSecurityToken( issuer, audience, // null if _options.NeedAudienceToBeChecked is false new ClaimsIdentity(claims), utcNow, utcNow + accessTokenExpiryTime, utcNow, signingCredentials, encryptingCredentials ); return(handler.WriteToken(token)); }
/// <summary> /// CreateAsync /// </summary> /// <param name="userGuid"></param> /// <param name="deviceId"></param> /// <param name="deviceType"></param> /// <param name="deviceVersion"></param> /// <param name="deviceAddress"></param> /// <param name="ipAddress"></param> /// <param name="expireTimeSpan"></param> /// <param name="transContext"></param> /// <returns></returns> /// <exception cref="HB.Framework.Common.ValidateErrorException"></exception> /// <exception cref="DatabaseException"></exception> public async Task <SignInToken> CreateAsync(string userGuid, string deviceId, string deviceType, string deviceVersion, /*string deviceAddress,*/ string ipAddress, TimeSpan expireTimeSpan, TransactionContext?transContext = null) { SignInToken token = new SignInToken { Guid = SecurityUtil.CreateUniqueToken(), UserGuid = userGuid, RefreshToken = SecurityUtil.CreateUniqueToken(), RefreshCount = 0, Blacked = false, DeviceId = deviceId, DeviceType = deviceType, DeviceVersion = deviceVersion, //DeviceAddress = deviceAddress, DeviceIp = ipAddress, ExpireAt = DateTimeOffset.UtcNow + expireTimeSpan }; await _db.AddAsync(token, transContext).ConfigureAwait(false); return(token); }
/// <summary> /// SignInAsync /// </summary> /// <param name="context"></param> /// <param name="lastUser"></param> /// <returns></returns> /// <exception cref="IdentityException"></exception> /// <exception cref="DatabaseException"></exception> /// <exception cref="KVStoreException"></exception> /// <exception cref="CacheException"></exception> public async Task <UserAccessResult> SignInAsync(SignInContext context, string lastUser) { ThrowIf.NotValid(context, nameof(context)); switch (context.SignInType) { case SignInType.ByMobileAndPassword: ThrowIf.NullOrEmpty(context.Mobile, "SignInContext.Mobile"); ThrowIf.NullOrEmpty(context.Password, "SignInContext.Password"); break; case SignInType.BySms: ThrowIf.NullOrEmpty(context.Mobile, "SignInContext.Mobile"); break; case SignInType.ByLoginNameAndPassword: ThrowIf.NullOrEmpty(context.LoginName, "SignInContext.LoginName"); ThrowIf.NullOrEmpty(context.Password, "SignInContext.Password"); break; default: break; } TransactionContext transactionContext = await _transaction.BeginTransactionAsync <SignInToken>().ConfigureAwait(false); try { //查询用户 User?user = context.SignInType switch { SignInType.ByLoginNameAndPassword => await _userRepo.GetByLoginNameAsync(context.LoginName !, transactionContext).ConfigureAwait(false), SignInType.BySms => await _userRepo.GetByMobileAsync(context.Mobile !, transactionContext).ConfigureAwait(false), SignInType.ByMobileAndPassword => await _userRepo.GetByMobileAsync(context.Mobile !, transactionContext).ConfigureAwait(false), _ => null }; //不存在,则新建用户 if (user == null && context.SignInType == SignInType.BySms) { user = await _identityService.CreateUserAsync(context.Mobile !, null, context.LoginName, context.Password, true, false, lastUser, transactionContext).ConfigureAwait(false); } if (user == null) { throw Exceptions.AuthorizationNotFound(signInContext: context); } UserLoginControl userLoginControl = await GetOrCreateUserLoginControlAsync(lastUser, user.Id).ConfigureAwait(false); //密码检查 if (context.SignInType == SignInType.ByMobileAndPassword || context.SignInType == SignInType.ByLoginNameAndPassword) { if (!PassowrdCheck(user, context.Password !)) { await OnSignInFailedAsync(userLoginControl, lastUser).ConfigureAwait(false); throw Exceptions.AuthorizationPasswordWrong(signInContext: context); } } //其他检查 await PreSignInCheckAsync(user, userLoginControl, lastUser).ConfigureAwait(false); //注销其他客户端 await DeleteSignInTokensAsync(user.Id, context.DeviceInfos.Idiom, context.LogOffType, context.DeviceInfos.Name, transactionContext).ConfigureAwait(false); //创建Token SignInToken signInToken = new SignInToken ( userId: user.Id, refreshToken: SecurityUtil.CreateUniqueToken(), expireAt: TimeUtil.UtcNow + (context.RememberMe ? _options.SignInOptions.RefreshTokenLongExpireTimeSpan : _options.SignInOptions.RefreshTokenShortExpireTimeSpan), deviceId: context.DeviceId, deviceVersion: context.DeviceVersion, deviceIp: context.DeviceIp, deviceName: context.DeviceInfos.Name, deviceModel: context.DeviceInfos.Model, deviceOSVersion: context.DeviceInfos.OSVersion, devicePlatform: context.DeviceInfos.Platform, deviceIdiom: context.DeviceInfos.Idiom, deviceType: context.DeviceInfos.Type ); await _signInTokenRepo.AddAsync(signInToken, lastUser, transactionContext).ConfigureAwait(false); //构造 Jwt string jwt = await ConstructJwtAsync(user, signInToken, context.SignToWhere, transactionContext).ConfigureAwait(false); UserAccessResult result = new UserAccessResult ( accessToken: jwt, refreshToken: signInToken.RefreshToken, currentUser: user ); await _transaction.CommitAsync(transactionContext).ConfigureAwait(false); return(result); } catch { await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false); throw; } }
private static IEnumerable <Claim> ConstructClaims(User user, IEnumerable <Role> roles, IEnumerable <UserClaim> userClaims, SignInToken signInToken) { IList <Claim> claims = new List <Claim> { new Claim(ClaimExtensionTypes.UserId, user.Id.ToString(GlobalSettings.Culture)), new Claim(ClaimExtensionTypes.SecurityStamp, user.SecurityStamp), new Claim(ClaimExtensionTypes.LoginName, user.LoginName ?? ""), new Claim(ClaimExtensionTypes.SignInTokenId, signInToken.Id.ToString(GlobalSettings.Culture)), new Claim(ClaimExtensionTypes.DeviceId, signInToken.DeviceId), }; foreach (UserClaim item in userClaims) { if (item.AddToJwt) { claims.Add(new Claim(item.ClaimType, item.ClaimValue)); } } foreach (Role item in roles) { claims.Add(new Claim(ClaimExtensionTypes.Role, item.Name)); } return(claims); }
public async Task <string> BuildJwtAsync <TUserClaim, TRole, TRoleOfUser>(IdenityUser user, SignInToken signInToken, string?audience) where TUserClaim : IdentityUserClaim, new() where TRole : IdentityRole, new() where TRoleOfUser : IdentityRoleOfUser, new() { DateTime utcNow = DateTime.UtcNow; IEnumerable <Claim> userClaims = await _identityService.GetUserClaimAsync <TUserClaim, TRole, TRoleOfUser>(user).ConfigureAwait(false); IList <Claim> claims = userClaims.ToList(); claims.Add(new Claim(ClaimExtensionTypes.SignInTokenGuid, signInToken.Guid)); //这个JWT只能在当前DeviceId上使用 claims.Add(new Claim(ClaimExtensionTypes.DeviceId, signInToken.DeviceId)); JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); JwtSecurityToken token = handler.CreateJwtSecurityToken( _options.OpenIdConnectConfiguration.Issuer, _options.NeedAudienceToBeChecked ? audience : null, new ClaimsIdentity(claims), utcNow, utcNow + _signInOptions.AccessTokenExpireTimeSpan, utcNow, _signingCredentials ); return(handler.WriteToken(token)); }
public static IEnumerable <Claim> GetClaims(User user, IEnumerable <Role> roles, IEnumerable <UserClaim> userClaims, SignInToken signInToken) { IList <Claim> claims = new List <Claim> { new Claim(ClaimExtensionTypes.UserGuid, user.Guid), new Claim(ClaimExtensionTypes.SecurityStamp, user.SecurityStamp), //new Claim(ClaimExtensionTypes.UserId, user.Id.ToString(GlobalSettings.Culture)), new Claim(ClaimExtensionTypes.LoginName, user.LoginName ?? ""), //new Claim(ClaimExtensionTypes.MobilePhone, user.Mobile??""), //new Claim(ClaimExtensionTypes.IsMobileConfirmed, user.MobileConfirmed.ToString(GlobalSettings.Culture)) }; foreach (UserClaim item in userClaims) { if (item.AddToJwt) { claims.Add(new Claim(item.ClaimType, item.ClaimValue)); } } foreach (Role item in roles) { claims.Add(new Claim(ClaimExtensionTypes.Role, item.Name)); } claims.Add(new Claim(ClaimExtensionTypes.SignInTokenGuid, signInToken.Guid)); claims.Add(new Claim(ClaimExtensionTypes.DeviceId, signInToken.DeviceId)); return(claims); }
public async Task <SignInResult> SignInAsync(SignInContext context, string lastUser) { ThrowIf.NotValid(context); switch (context.SignInType) { case SignInType.ByMobileAndPassword: ThrowIf.NullOrEmpty(context.Mobile, "SignInContext.Mobile"); ThrowIf.NullOrEmpty(context.Password, "SignInContext.Password"); break; case SignInType.BySms: ThrowIf.NullOrEmpty(context.Mobile, "SignInContext.Mobile"); break; case SignInType.ByLoginNameAndPassword: ThrowIf.NullOrEmpty(context.LoginName, "SignInContext.LoginName"); ThrowIf.NullOrEmpty(context.Password, "SignInContext.Password"); break; default: break; } TransactionContext transactionContext = await _transaction.BeginTransactionAsync <SignInToken>().ConfigureAwait(false); try { //查询用户 User?user = context.SignInType switch { SignInType.ByLoginNameAndPassword => await _identityService.GetUserByLoginNameAsync(context.LoginName !).ConfigureAwait(false), SignInType.BySms => await _identityService.GetUserByMobileAsync(context.Mobile !).ConfigureAwait(false), SignInType.ByMobileAndPassword => await _identityService.GetUserByMobileAsync(context.Mobile !).ConfigureAwait(false), _ => null }; //不存在,则新建用户 bool newUserCreated = false; if (user == null && context.SignInType == SignInType.BySms) { user = await _identityService.CreateUserAsync( mobile : context.Mobile !, email : null, loginName : context.LoginName, password : context.Password, mobileConfirmed : true, emailConfirmed : false, lastUser : lastUser).ConfigureAwait(false); newUserCreated = true; } if (user == null) { throw new AuthorizationException(ErrorCode.AuthorizationNotFound, $"SignInContext:{SerializeUtil.ToJson(context)}"); } //密码检查 if (context.SignInType == SignInType.ByMobileAndPassword || context.SignInType == SignInType.ByLoginNameAndPassword) { if (!PassowrdCheck(user, context.Password !)) { await OnPasswordCheckFailedAsync(user, lastUser).ConfigureAwait(false); throw new AuthorizationException(ErrorCode.AuthorizationPasswordWrong, $"SignInContext:{SerializeUtil.ToJson(context)}"); } } //其他检查 await PreSignInCheckAsync(user, lastUser).ConfigureAwait(false); //注销其他客户端 await _signInTokenBiz.DeleteByLogOffTypeAsync(user.Guid, context.DeviceInfos.Idiom, context.LogOffType, context.DeviceInfos.Name, transactionContext).ConfigureAwait(false); //创建Token SignInToken userToken = await _signInTokenBiz.CreateAsync( user.Guid, context.DeviceId, context.DeviceInfos, context.DeviceVersion, //context.DeviceAddress, context.DeviceIp, context.RememberMe?_options.SignInOptions.RefreshTokenLongExpireTimeSpan : _options.SignInOptions.RefreshTokenShortExpireTimeSpan, lastUser, transactionContext).ConfigureAwait(false); //构造 Jwt IEnumerable <Claim> claims = GetClaims(user, transactionContext); SignInResult result = new SignInResult ( accessToken: await JwtHelper.BuildJwt(user, userToken, context.SignToWhere).ConfigureAwait(false), refreshToken: userToken.RefreshToken, newUserCreated: newUserCreated, currentUser: user ); await _transaction.CommitAsync(transactionContext).ConfigureAwait(false); return(result); } catch { await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false); throw; } }
/// <summary> /// UpdateAsync /// </summary> /// <param name="signInToken"></param> /// <param name="transContext"></param> /// <returns></returns> /// <exception cref="HB.Framework.Common.ValidateErrorException"></exception> /// <exception cref="DatabaseException"></exception> public Task UpdateAsync(SignInToken signInToken, TransactionContext?transContext = null) { return(_db.UpdateAsync(signInToken, transContext)); }
/// <summary> /// SignInAsync /// </summary> /// <param name="context"></param> /// <returns></returns> /// <exception cref="HB.Framework.Common.ValidateErrorException"></exception> /// <exception cref="HB.Component.Authorization.AuthorizationException"></exception> /// <exception cref="DatabaseException"></exception> public async Task <SignInResult> SignInAsync <TUser, TUserClaim, TRole, TRoleOfUser>(SignInContext context) where TUser : IdenityUser, new() where TUserClaim : IdentityUserClaim, new() where TRole : IdentityRole, new() where TRoleOfUser : IdentityRoleOfUser, new() { ThrowIf.NotValid(context); switch (context.SignInType) { case SignInType.ByMobileAndPassword: ThrowIf.NullOrEmpty(context.Mobile, "SignInContext.Mobile"); ThrowIf.NullOrEmpty(context.Password, "SignInContext.Password"); break; case SignInType.BySms: ThrowIf.NullOrEmpty(context.Mobile, "SignInContext.Mobile"); break; case SignInType.ByLoginNameAndPassword: ThrowIf.NullOrEmpty(context.LoginName, "SignInContext.LoginName"); ThrowIf.NullOrEmpty(context.Password, "SignInContext.Password"); break; default: break; } TransactionContext transactionContext = await _database.BeginTransactionAsync <SignInToken>(IsolationLevel.ReadCommitted).ConfigureAwait(false); try { //查询用户 TUser?user = context.SignInType switch { SignInType.ByLoginNameAndPassword => await _identityService.GetUserByLoginNameAsync <TUser>(context.LoginName !).ConfigureAwait(false), SignInType.BySms => await _identityService.GetUserByMobileAsync <TUser>(context.Mobile !).ConfigureAwait(false), SignInType.ByMobileAndPassword => await _identityService.GetUserByMobileAsync <TUser>(context.Mobile !).ConfigureAwait(false), _ => null }; //不存在,则新建用户 bool newUserCreated = false; if (user == null && context.SignInType == SignInType.BySms) { user = await _identityService.CreateUserByMobileAsync <TUser>(context.Mobile !, context.LoginName, context.Password, true).ConfigureAwait(false); newUserCreated = true; } if (user == null) { throw new AuthorizationException(ErrorCode.AuthorizationNotFound, $"SignInContext:{SerializeUtil.ToJson(context)}"); } //密码检查 if (context.SignInType == SignInType.ByMobileAndPassword || context.SignInType == SignInType.ByLoginNameAndPassword) { if (!PassowrdCheck(user, context.Password !)) { await OnPasswordCheckFailedAsync(user).ConfigureAwait(false); throw new AuthorizationException(ErrorCode.AuthorizationPasswordWrong, $"SignInContext:{SerializeUtil.ToJson(context)}"); } } //其他检查 await PreSignInCheckAsync(user).ConfigureAwait(false); //注销其他客户端 DeviceType clientType = DeviceTypeChecker.Check(context.DeviceType); if (clientType != DeviceType.Web && _signInOptions.AllowOnlyOneAppClient) { await _signInTokenBiz.DeleteAppClientTokenByUserGuidAsync(user.Guid, transactionContext).ConfigureAwait(false); } //创建Token SignInToken userToken = await _signInTokenBiz.CreateAsync( user.Guid, context.DeviceId, clientType.ToString(), context.DeviceVersion, //context.DeviceAddress, context.DeviceIp, context.RememberMe?_signInOptions.RefreshTokenLongExpireTimeSpan : _signInOptions.RefreshTokenShortExpireTimeSpan, transactionContext).ConfigureAwait(false); await _database.CommitAsync(transactionContext).ConfigureAwait(false); //构造 Jwt SignInResult result = new SignInResult ( accessToken: await _jwtBuilder.BuildJwtAsync <TUserClaim, TRole, TRoleOfUser>(user, userToken, context.SignToWhere).ConfigureAwait(false), refreshToken: userToken.RefreshToken, newUserCreated: newUserCreated, currentUser: user ); return(result); } catch { await _database.RollbackAsync(transactionContext).ConfigureAwait(false); throw; } }