Autenticação JWT para Asp.Net Api Web
vejo suporte para .net core
e para OWIN
aplicações.
Estou neste momento a apresentar a minha candidatura no IIS
.
Como posso obter este módulo de autenticação na minha aplicação? Existe alguma forma de eu poder usar a configuração <authentication>
semelhante à forma como eu uso a autenticação\windows do formulário?
3 answers
Https://tools.ietf.org/html/rfc7519
Basicamente, um símbolo JWT parece:
<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>
Exemplo:
EyJhbGciOiJIUzI1NiIsInR5cCI6IkpXvcj9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmjmijoxndc3nty1nzi0lcjlehaioje0nzc1njy5mjqsimlhdci6mtq3nzu2ntcynh0.6MzD1VwA5AcOcajkFyKhLYybr3h13iZjdyhm9zysdfq
O símbolo JWT tem três secções:
- cabeçalho: formato JSON que é codificado como um base64
- reivindicações: formato JSON que está codificado como base64.
- assinatura: criada e assinada com base no cabeçalho e reivindicações codificadas como base64.
Se utilizar o sítio web jwt.io com o símbolo acima, você pode descodificar e ver o símbolo como abaixo:
Tecnicamente, o JWT usa a assinatura que é assinada pelos cabeçalhos e reivindicações com o algoritmo de segurança especificado nos cabeçalhos (exemplo: HMACSHA256). Por conseguinte, a JWT deve ser transferida através dos HTTPs se você armazenar qualquer informação sensível em reivindicações.
Agora, para usar a autenticação JWT, você realmente não precisa de um middleware OWIN se você tem um sistema de Api Web legado. O conceito simples é como fornecer token JWT e como validar token quando o pedido vem. É isso.
De volta para a demo, para manter o token JWT leve, só guardo username
e expiration time
em JWT. Mas desta forma, você tem que refazer a nova identidade local (principal) para adicionar mais informações como: papéis.. se quero fazer a autorização do papel. Mas, se quiser adicionar mais informação ao JWT, é consigo, muito flexível.
Em vez de usar o middleware OWIN, pode simplesmente fornecer o ponto final do token JWT usando a acção do controlador:
public class TokenController : ApiController
{
// This is naive endpoint for demo, it should use Basic authentication to provide token or POST request
[AllowAnonymous]
public string Get(string username, string password)
{
if (CheckUser(username, password))
{
return JwtManager.GenerateToken(username);
}
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
public bool CheckUser(string username, string password)
{
// should check in the database
return true;
}
}
Esta é uma acção ingênua, na produção deve usar o POST request ou o Basic Authentication endpoint para fornecer o JWT token.
Como gerar o token baseado emusername
?
Pode utilizar o pacote NuGet chamado System.IdentityModel.Tokens.Jwt
de MS para gerar o token, ou mesmo outro pacote, se quiser. Na demo, eu uso HMACSHA256
com SymmetricKey
:
/// <summary>
/// Use the below code to generate symmetric Secret Key
/// var hmac = new HMACSHA256();
/// var key = Convert.ToBase64String(hmac.Key);
/// </summary>
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";
public static string GenerateToken(string username, int expireMinutes = 20)
{
var symmetricKey = Convert.FromBase64String(Secret);
var tokenHandler = new JwtSecurityTokenHandler();
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
}),
Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)
};
var stoken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(stoken);
return token;
}
O objectivo para fornecer o token JWT está feito, agora, como validar o JWT quando o pedido chegar, na demo que eu construí
JwtAuthenticationAttribute
que herda de IAuthenticationFilter
, mais detalhes sobre o filtro de autenticação em aqui .
Com este atributo, você pode autenticar qualquer acção, basta colocar este atributo nessa acção.
public class ValueController : ApiController
{
[JwtAuthentication]
public string Get()
{
return "value";
}
}
Também pode usar o OWIN middleware ou DelegateHander se quiser validar todos os pedidos recebidos para a sua WebApi (não específico no controlador ou acção)
Abaixo está o método principal do filtro de autenticação:
private static bool ValidateToken(string token, out string username)
{
username = null;
var simplePrinciple = JwtManager.GetPrincipal(token);
var identity = simplePrinciple.Identity as ClaimsIdentity;
if (identity == null)
return false;
if (!identity.IsAuthenticated)
return false;
var usernameClaim = identity.FindFirst(ClaimTypes.Name);
username = usernameClaim?.Value;
if (string.IsNullOrEmpty(username))
return false;
// More validate to check whether username exists in system
return true;
}
protected Task<IPrincipal> AuthenticateJwtToken(string token)
{
string username;
if (ValidateToken(token, out username))
{
// based on username to get more information from database in order to build local identity
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
// Add more claims if needed: Roles, ...
};
var identity = new ClaimsIdentity(claims, "Jwt");
IPrincipal user = new ClaimsPrincipal(identity);
return Task.FromResult(user);
}
return Task.FromResult<IPrincipal>(null);
}
O fluxo de trabalho é, usando a biblioteca JWT (pacote NuGet acima) para validar o item JWT e depois voltar ClaimsPrincipal
. Você pode realizar mais validação, como verificar se o usuário existe no seu sistema e adicionar outras validações personalizadas, se quiser. O código para validar o token JWT e obter o principal verso:
public static ClaimsPrincipal GetPrincipal(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
if (jwtToken == null)
return null;
var symmetricKey = Convert.FromBase64String(Secret);
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
return principal;
}
catch (Exception)
{
//should write log
return null;
}
}
Se o token JWT for validado e o principal for devolvido, você deve construir uma nova identidade local e colocar mais informações nele para verificar a autorização do papel.
Lembre-se de adicionar config.Filters.Add(new AuthorizeAttribute());
(autorização por omissão) no âmbito global, a fim de evitar qualquer pedido anónimo aos seus recursos.
Pode usar o carteiro para testar a demonstração:
Peça token (ingênuo como mencionei acima, apenas para demonstração):
GET http://localhost:{port}/api/token?username=cuong&password=1
Coloque o token JWT no cabeçalho para pedido autorizado, exemplo:
GET http://localhost:{port}/api/value
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s
A demo está aqui. https://github.com/cuongle/WebApi.Jwt
Eu acho que você deve usar algum servidor de festa 3d para suportar o token JWT e não há nenhum suporte fora da caixa JWT na API 2 WEB.
No entanto, existe um projecto OWIN para apoiar algum formato de Símbolo assinado (não JWT). Ele funciona como um protocolo OAuth reduzido para fornecer apenas uma forma simples de autenticação para um site web.
Pode ler mais sobre ele, por exemplo aqui .
É bastante longo,mas a maioria das peças são detalhes com controladores e ... ASP.NET identidade que podes não precisar de nada. Os mais importantes sãoPasso 9: Adicionar suporte para a geração de Tokens ao portador de OAuth
Passo 12: testar a API traseira
Aí você pode ler como configurar o endpoint (por exemplo, "/token") que você pode acessar a partir do frontend (e detalhes sobre o formato do pedido).
Outras etapas fornecem detalhes sobre como ligar esse parâmetro à base de dados, etc. e podes escolher as partes de que precisas.
Eu também implementei a API do Jason Web Token no meu projecto, você pode baixar a partir deste link JWT API Token .
Pode utilizar [authorize]
para verificar se um Utilizador está autenticado ou não?