У меня есть работающий веб-сайт только для членов, который работает так, как должен, с входом в систему и т. д. Теперь мне нужно поддерживать единый вход, где я получу имя пользователя профиля в токене JWT, а затем войду в систему. Внешняя система, которая отправит этот запрос, НЕ знает никакой другой информации, кроме имени пользователя, поэтому пароль не передается в токен, и это невозможно.
JWT был выбран в качестве предпочтительного метода для обеспечения этого. Мы собираемся использовать секретный ключ для обмена информацией, секретный ключ, конечно же, известен только отправителю и получателю.
Я ищу простой пример того, как это может выглядеть с точки зрения кода, как на стороне отправителя, так и на стороне получателя. Концом получателя будет конечная точка WebAPI, которая будет обрабатывать вход в систему, а затем перенаправлять на главную страницу веб-сайта только для членов, если вход в систему выполнен успешно.
Он разработан на C#.
Ваши сети csr или ssr с C#? Сколько веб-сайтов и микросервисов в вашей инфраструктуре? Вы ищете стратегию предприятия или просто poc?
@JRichardsz это SSR с C# на приемном конце. Просто простой POC, чтобы помочь с моим собственным пониманием лучшего решения и способа справиться с задачей. У меня есть сам логин, поэтому у меня есть код, который может принимать только имя пользователя, а затем регистрировать пользователя. Шаг, который мне не хватает, — это шифрование и дешифрование данных JWT с использованием секретного ключа.
Обычно и часто пользователь/пароль заменяются на новый JWT.
JWT не должен хранить ничего разумного, например, пароль. Но некоторые компании вроде Microsoft хранят не осмысленные значения, а много информации https://gist.github.com/jrichardsz/6512f9b2b4c38620bf00e24c71b6cf2d
Для предприятий процесс шифрования и дешифрования не должен выполняться на уровне микросервиса. Это должно выполняться другим сервером, например: Auth0, okta, Keycloack и т. д.
Ваш микросервис только получает токен и отправляет его на платформу безопасности. Лучший способ сделать это — использовать промежуточное ПО на любом языке. Это для c#
Платформа безопасности возвращает ответ с данными в синтаксисе, который клиент (С# в вашем случае) понимает, является ли токен законным, действительным, не просроченным, существует пользователь, пользователю разрешено выполнять операцию и т. д. Я использовал это в некоторой реализации в на что я сказал: «Пользователю разрешено выполнять эту операцию, и это его имя пользователя»
конечная точка: acme-security.com/v1/oauth2/token/validate
просьба: eyJ0eXAiOiJKV1Qi...
отклик:
{
"isAllowed": true,
"subject": "[email protected]"
}
Также вы можете сделать это с помощью API-шлюза.
В более реальном сценарии нам нужно больше, чем простая проверка jwt. Нам нужно убедиться, что пользователю admin/guest разрешено выполнять определенные конечные точки. Мы не хотим, чтобы сотрудник напрямую вызывал конечную точку платежа, устанавливающую свою зарплату :/
Следуйте спецификации oauth2, если вы будете внедрять собственную платформу безопасности.
Jwt должен быть отправлен как заголовок авторизации
ВАЖНО: если вы будете реализовывать собственную генерацию и проверку jwt, используйте переменные ENV, чтобы скрыть секрет и максимально защитить его для вашей производственной среды.
Если предыдущие шаги понятны, вам нужен только один из этих подходов:
Генерация JWT
public string GenerateToken(User user)
{
// generate token that is valid for 7 days
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(SUPER_SECRET_KEY);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
JWT-декодирование или проверка
public int? ValidateToken(string token)
{
if (token == null)
return null;
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(SUPER_SECRET_KEY);
try
{
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
// set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);
var jwtToken = (JwtSecurityToken)validatedToken;
var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);
// return user id from JWT token if validation successful
return userId;
}
catch
{
// return null if validation fails
return null;
}
}
Этот код выдает ошибки, когда срок действия токена истек или какой-то приятель пытается отправить jwt без вашего SUPER_SECRET_KEY.
Вы можете использовать эти фрагменты непосредственно при генерации токенов и внутри своих конечных точек.
[HttpGet]
public ActionResult<List<Dictionary<string, object>>> findAllEmployees()
{
//get jwt from http received headers
validationResponse = ValidateToken(jwt)
//if you have a security platform, callhere instead
//ValidateToken(jwt)
//if validationResponse.isAllowed ....
var list = this.employeeService.findAllEmployees();
return Ok(list);
}
или с промежуточным программным обеспечением, таким как профессионал, чтобы содержать в чистоте ваши окончательные контроллеры
«Я ищу простой пример того, как это может выглядеть с точки зрения кода» — такой вещи не существует: просто слишком много движущихся частей. Кроме того, пожалуйста, уточните, что именно вы подразумеваете под «единым входом», потому что тот факт, что вы используете JWT, не означает, например, что вы используете свой собственный IdP OIDC.