Безопасность на уровне строк с помощью session_context не работает после обновления токенаC#

Место общения программистов C#
Anonymous
Безопасность на уровне строк с помощью session_context не работает после обновления токена

Сообщение Anonymous »

У меня многопользовательская база данных, я использую безопасность на уровне строк для фильтрации/блокировки данных для каждой таблицы. Каждый раз, когда кто-то запрашивает таблицу, ему необходимо настроить контекст сеанса. У меня настроен API, с помощью которого пользователи могут входить в систему и запускать получение/отправку данных. Как только пользователь входит в систему, я добавляю идентификатор пользователя в статический класс. Я использую это при настройке сеанса (см. ниже).
Я также реализовал токены JWT и обновления. Каждый запрос API защищен.
Проблема в том, что когда пользователь отправляет запрос к API в первый раз, используя токен JWT, он получает правильный ответ. РЛС работает как надо. Он возвращает строки только для этого пользователя. Но когда пользователь обновляет токен и использует обновленный токен, результаты возвращаются как 200, но они пусты.
Я предполагаю, что проблема связана с контекстом сеанса, поскольку токен JWT был уполномочен отправить запрос. Это RLS возвращает пустую таблицу.
Код для настройки сеанса в .NET:

Код: Выделить всё

using (SqlCommand command =new SqlCommand("EXEC sp_set_session_context @key=N'UserId', @value=@UserId", conn))
{
command.Parameters.AddWithValue("@UserId", LoggedInUser.UserId);
command.ExecuteNonQuery();
}
Обновить код токена:

Код: Выделить всё

public async Task RefreshTokenAsync(string refreshtoken)
{
var refreshToken = await context.RefreshTokens.FirstOrDefaultAsync(r => r.Token == refreshtoken);
//Some checks on the validation of the refresh token like if it's expired etc.
var getUser = await userManager.FindByIdAsync(refreshToken.UserId);
var getUserRole = await userManager.GetRolesAsync(getUser);
var userSession = new UserSession(getUser.Id, getUser.Name, getUser.Email, getUserRole.First());
context.RefreshTokens.Remove(refreshToken);
return await GenerateJwtTokenAsync(userSession, deviceid);
}

public async Task GenerateJwtTokenAsync(UserSession user)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Name),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Email, user.Email),
new Claim(ClaimTypes.Role,user.Role)
};

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"]!));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
issuer: config["Jwt:Issuer"],
audience: config["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(5),
signingCredentials: creds);

var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);

var refreshToken = new RefreshToken
{
Token = Guid.NewGuid().ToString(),
JwtId = token.Id,
IsRevoked = false,
UserId = user.Id,
AddedDate = DateTime.UtcNow,
ExpiryDate = DateTime.UtcNow.AddMonths(1)
};

await context.RefreshTokens.AddAsync(refreshToken);
await context.SaveChangesAsync();

return new AuthResult
{
Token = jwtToken,
RefreshToken = refreshToken.Token,
Success = true
};
}
Код для входа в систему — единственное место, где я устанавливаю идентификатор пользователя:

Код: Выделить всё

private async Task LoginAccountAsync(Login login)
{
var getUser = await userManager.FindByEmailAsync(login.Email);

var getUserRole = await userManager.GetRolesAsync(getUser);
var userSession = new UserSession(getUser.Id, getUser.Name, getUser.Email, getUserRole.First());
ApplicationUser getUser = response.User;

bool checkUserPassword = await userManager.CheckPasswordAsync(getUser, login.Password);
//Some checks...
LoggedInUser.UserId = getUser.Id; //Setting the LoggedInUser static class.
return await GenerateJwtTokenAsync(userSession);
}
Я попытался отладить его, вернув контекст сеанса из базы данных после выполнения другого запроса, и он вернул правильный сеанс. Я выполнил запрос в SQL, настроив тот же контекст сеанса, и он вернул правильные результаты. Кроме того, это работает должным образом до вызова токена обновления.
Может ли кто-нибудь обнаружить проблему? Как мне отладить эту проблему? Есть ли способ отладить его в базе данных, чтобы просмотреть все выполненные запросы?
Я столкнулся с этой проблемой, используя опубликованную базу данных Azure (тестовую). Я протестировал его с использованием локальной базы данных, и, похоже, никаких проблем не возникло.
Изменить
Полный код, который запускается при запросе база данных:

Код: Выделить всё

private static DataTable DoExecuteSQL(SqlCommand cmd, bool loadtable)
{
DataTable dt = new();

using (SqlConnection conn = new(ConnectionString))
{
conn.Open();
if (LoggedInUser.UserId != null)
{
using (SqlCommand command =new SqlCommand("EXEC sp_set_session_context @key=N'UserId', @value=@UserId", conn))
{
command.Parameters.AddWithValue("@UserId", LoggedInUser.UserId);
command.ExecuteNonQuery();
}
}

cmd.Connection = conn;
try
{
SqlDataReader dr = cmd.ExecuteReader();
if (loadtable)
{
dt.Load(dr);
}
}
catch (SqlException ex)
{
string msg = ParseConstraintMsg(ex.Message);
throw new Exception(msg);
}
catch (InvalidCastException ex)
{
throw new Exception(cmd.CommandText + ": " + ex.Message, ex);
}
}

return dt;
}
Затем я конвертирую его в объект, который возвращается в API.


Подробнее здесь: https://stackoverflow.com/questions/787 ... hing-token

Вернуться в «C#»