/// <summary>
        /// RefreshAccessTokenAsync
        /// </summary>
        /// <param name="context"></param>
        /// <param name="lastUser"></param>
        /// <returns></returns>
        /// <exception cref="IdentityException"></exception>
        /// <exception cref="DatabaseException"></exception>
        /// <exception cref="CacheException"></exception>
        public async Task <UserAccessResult> RefreshAccessTokenAsync(RefreshContext context, string lastUser)
        {
            ThrowIf.NotValid(context, nameof(context));

            //解决并发涌入
            using IDistributedLock distributedLock = await _lockManager.NoWaitLockAsync(
                      nameof (RefreshAccessTokenAsync) + context.DeviceId,
                      _options.RefreshIntervalTimeSpan, notUnlockWhenDispose : true).ConfigureAwait(false);

            if (!distributedLock.IsAcquired)
            {
                throw Exceptions.AuthorizationTooFrequent(context: context);
            }

            //AccessToken, Claims 验证

            ClaimsPrincipal?claimsPrincipal = null;

            try
            {
                claimsPrincipal = JwtHelper.ValidateTokenWithoutLifeCheck(context.AccessToken, _options.OpenIdConnectConfiguration.Issuer, _issuerSigningKeys, _decryptionSecurityKey);
            }
            catch (Exception ex)
            {
                throw Exceptions.AuthorizationInvalideAccessToken(context: context, innerException: ex);
            }

            //TODO: 这里缺DeviceId验证. 放在了StartupUtil.cs中

            if (claimsPrincipal == null)
            {
                //TODO: Black concern SigninToken by RefreshToken
                throw Exceptions.AuthorizationInvalideAccessToken(context: context);
            }

            if (claimsPrincipal.GetDeviceId() != context.DeviceId)
            {
                throw Exceptions.AuthorizationInvalideDeviceId(context: context);
            }

            long userId = claimsPrincipal.GetUserId().GetValueOrDefault();

            if (userId <= 0)
            {
                throw Exceptions.AuthorizationInvalideUserId(context: context);
            }

            //SignInToken 验证
            User?              user;
            SignInToken?       signInToken        = null;
            TransactionContext transactionContext = await _transaction.BeginTransactionAsync <SignInToken>().ConfigureAwait(false);

            try
            {
                signInToken = await _signInTokenRepo.GetByConditionAsync(
                    claimsPrincipal.GetSignInTokenId().GetValueOrDefault(),
                    context.RefreshToken,
                    context.DeviceId,
                    userId,
                    transactionContext).ConfigureAwait(false);

                if (signInToken == null || signInToken.Blacked)
                {
                    throw Exceptions.AuthorizationNoTokenInStore(cause: "Refresh token error. signInToken not saved in db. ");
                }

                //验证SignInToken过期问题

                if (signInToken.ExpireAt < TimeUtil.UtcNow)
                {
                    throw Exceptions.AuthorizationRefreshTokenExpired();
                }

                // User 信息变动验证

                user = await _userRepo.GetByIdAsync(userId, transactionContext).ConfigureAwait(false);

                if (user == null || user.SecurityStamp != claimsPrincipal.GetUserSecurityStamp())
                {
                    throw Exceptions.AuthorizationUserSecurityStampChanged(cause: "Refresh token error. User SecurityStamp Changed.");
                }

                // 更新SignInToken
                signInToken.RefreshCount++;

                await _signInTokenRepo.UpdateAsync(signInToken, lastUser, transactionContext).ConfigureAwait(false);

                // 发布新的AccessToken

                string accessToken = await ConstructJwtAsync(user, signInToken, claimsPrincipal.GetAudience(), transactionContext).ConfigureAwait(false);

                await _transaction.CommitAsync(transactionContext).ConfigureAwait(false);

                return(new UserAccessResult(accessToken, context.RefreshToken, user));
            }
            catch
            {
                await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false);

                if (signInToken != null)
                {
                    await _signInTokenRepo.DeleteAsync(signInToken, lastUser, null).ConfigureAwait(false);
                }

                throw;
            }
        }
示例#2
0
        /// <summary>
        /// CosumeTaskProcedure
        /// </summary>


        private async Task CosumeAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    long now = TimeUtil.UtcNowUnixTimeSeconds;

                    //1, Get Entity
                    IDatabase database = await RedisInstanceManager.GetDatabaseAsync(_instanceSetting, _logger).ConfigureAwait(false);

                    RedisValue redisValue = await database.ListRightPopLeftPushAsync(RedisEventBusEngine.QueueName(_eventType), RedisEventBusEngine.HistoryQueueName(_eventType)).ConfigureAwait(false);

                    if (redisValue.IsNullOrEmpty)
                    {
                        _logger.LogTrace("ConsumeTask Sleep, {InstanceName}, {eventType}", _instanceSetting.InstanceName, _eventType);

                        await Task.Delay(_cONSUME_INTERVAL_SECONDS * 1000, cancellationToken).ConfigureAwait(false);

                        continue;
                    }

                    EventMessageEntity?entity = SerializeUtil.FromJson <EventMessageEntity>(redisValue);

                    if (entity == null)
                    {
                        _logger.LogCritical("有空EventMessageEntity, {eventType}, {value}", _eventType, redisValue);
                        continue;
                    }

                    using IDistributedLock distributedLock = await _lockManager.NoWaitLockAsync(
                              "eBusC_" + entity.Guid,
                              TimeSpan.FromSeconds(_options.EventBusConsumerAckTimeoutSeconds),
                              false,
                              cancellationToken).ConfigureAwait(false);

                    if (!distributedLock.IsAcquired)
                    {
                        //竟然有人在检查entity.Guid,好了,这下肯定有人在处理了,任务结束。哪怕那个人没处理成功,也没事,等着history吧。
                        continue;
                    }

                    //2, 过期检查

                    if (now - entity.Timestamp > _eventBusEventMessageExpiredSeconds)
                    {
                        _logger.LogCritical("有EventMessage过期,{eventType}, {entity}", _eventType, SerializeUtil.ToJson(entity));

                        await distributedLock.DisposeAsync().ConfigureAwait(false);

                        continue;
                    }

                    //3, 防重检查

                    string AcksSetName = RedisEventBusEngine.AcksSetName(_eventType);

                    bool?isExist = await IsAcksExistedAsync(database, AcksSetName, entity.Guid).ConfigureAwait(false);

                    if (isExist == null || isExist.Value)
                    {
                        _logger.LogInformation("有EventMessage重复,{eventType}, {entity}", _eventType, SerializeUtil.ToJson(entity));

                        await distributedLock.DisposeAsync().ConfigureAwait(false);

                        continue;
                    }

                    //4, Handle Entity
                    try
                    {
                        await _eventHandler.HandleAsync(entity.JsonData, cancellationToken).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogCritical(ex, "处理消息出错, {_eventType}, {entity}", _eventType, SerializeUtil.ToJson(entity));
                    }

                    //5, Acks
                    await AddAcksAsync(now, database, AcksSetName, entity.Guid, entity.Timestamp).ConfigureAwait(false);

                    _logger.LogTrace("Consume Task For {eventType} Stopped.", _eventType);
                }
                catch (RedisConnectionException ex)
                {
                    _logger.LogError(ex, "Consume 中出现Redis链接问题. {eventType}", _eventType);
                    await Task.Delay(5000, cancellationToken).ConfigureAwait(false);
                }
                catch (RedisTimeoutException ex)
                {
                    _logger.LogError(ex, "Consume 中出现Redis超时问题. {eventType}", _eventType);
                }
                catch (Exception ex)
                {
                    _logger.LogCritical(ex, "Consume 出现未知问题. {eventType}", _eventType);
                }
            }
        }
示例#3
0
        //TODO: 做好详细的历史纪录,各个阶段都要打log。一有风吹草动,就立马删除SignInToken
        /// <returns>新的AccessToken</returns>
        public async Task <string> RefreshAccessTokenAsync(RefreshContext context, string lastUser)
            where User : User, new()
            where TUserClaim : UserClaim, new()
            where TRole : Role, new()
            where TRoleOfUser : RoleOfUser, new()
        {
            ThrowIf.NotValid(context);

            //解决并发涌入
            using IDistributedLock distributedLock = await _lockManager.NoWaitLockAsync(
                      nameof (RefreshAccessTokenAsync) + context.DeviceId,
                      _options.RefreshIntervalTimeSpan).ConfigureAwait(false);

            if (!distributedLock.IsAcquired)
            {
                throw new AuthorizationException(ErrorCode.AuthorizationTooFrequent, $"Context:{SerializeUtil.ToJson(context)}");
            }

            //AccessToken, Claims 验证

            ClaimsPrincipal?claimsPrincipal = null;

            try
            {
                claimsPrincipal = ValidateTokenWithoutLifeCheck(context);
            }
            catch (Exception ex)
            {
                throw new AuthorizationException(ErrorCode.AuthorizationInvalideAccessToken, $"Context: {SerializeUtil.ToJson(context)}", ex);
            }

            //TODO: 这里缺DeviceId验证. 放在了StartupUtil.cs中

            if (claimsPrincipal == null)
            {
                //TODO: Black concern SigninToken by RefreshToken
                throw new AuthorizationException(ErrorCode.AuthorizationInvalideAccessToken, $"Context: {SerializeUtil.ToJson(context)}");
            }

            if (claimsPrincipal.GetDeviceId() != context.DeviceId)
            {
                throw new AuthorizationException(ErrorCode.AuthorizationInvalideDeviceId, $"Context: {SerializeUtil.ToJson(context)}");
            }

            string?userGuid = claimsPrincipal.GetUserGuid();

            if (string.IsNullOrEmpty(userGuid))
            {
                throw new AuthorizationException(ErrorCode.AuthorizationInvalideUserGuid, $"Context: {SerializeUtil.ToJson(context)}");
            }


            //SignInToken 验证
            User?       user;
            SignInToken?signInToken;

            //TransactionContext transactionContext = await _transaction.BeginTransactionAsync<SignInToken>().ConfigureAwait(false);

            try
            {
                signInToken = await _signInTokenBiz.GetAsync(
                    claimsPrincipal.GetSignInTokenGuid(),
                    context.RefreshToken,
                    context.DeviceId,
                    userGuid,


                    ).ConfigureAwait(false);

                if (signInToken == null || signInToken.Blacked)
                {
                    //await _database.RollbackAsync(transactionContext).ConfigureAwait(false);

                    throw new AuthorizationException(ErrorCode.AuthorizationNoTokenInStore, $"Refresh token error. signInToken not saved in db. ");
                }

                //验证SignInToken过期问题

                if (signInToken.ExpireAt < DateTimeOffset.UtcNow)
                {
                    //await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false);

                    await BlackSignInTokenAsync(signInToken, lastUser).ConfigureAwait(false);

                    throw new AuthorizationException(ErrorCode.AuthorizationRefreshTokenExpired, $"Refresh Token Expired.");
                }

                // User 信息变动验证

                user = await _identityService.GetUserByUserGuidAsync(userGuid).ConfigureAwait(false);

                if (user == null || user.SecurityStamp != claimsPrincipal.GetUserSecurityStamp())
                {
                    //await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false);

                    await BlackSignInTokenAsync(signInToken, lastUser).ConfigureAwait(false);

                    throw new AuthorizationException(ErrorCode.AuthorizationUserSecurityStampChanged, $"Refresh token error. User SecurityStamp Changed.");
                }

                // 更新SignInToken
                signInToken.RefreshCount++;

                await _signInTokenBiz.UpdateAsync(signInToken, lastUser, transactionContext).ConfigureAwait(false);

                await _transaction.CommitAsync(transactionContext).ConfigureAwait(false);
            }
            catch
            {
                await _transaction.RollbackAsync(transactionContext).ConfigureAwait(false);

                throw;
            }

            // 发布新的AccessToken

            return(await _jwtBuilder.BuildJwtAsync(user, signInToken, claimsPrincipal.GetAudience()).ConfigureAwait(false));
        }