Esempio n. 1
0
        /// <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;
            }
        }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 3
0
        /// <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;
            }
        }
Esempio n. 4
0
        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));
        }
Esempio n. 5
0
        /// <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);
        }
Esempio n. 6
0
        /// <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;
            }
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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));
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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;
            }
        }
Esempio n. 11
0
 /// <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));
 }
Esempio n. 12
0
        /// <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;
            }
        }