Mic*_*ael 18 c# access-token oauth-2.0 jwt asp.net-web-api
我有一个由Angular提供的Web API项目,我希望使用JWT令牌来保护它.我已经进行了用户/通过验证,所以我认为我只需要实现JWT部分.
我相信我已经确定了JwtAuthForWebAPI所以使用它的一个例子会很棒.
我假设任何未使用[Authorize]修饰的方法都会像往常一样运行,并且如果客户端传递的令牌不匹配,则[Authorize]修饰的任何方法都将为401.
我还不知道如何在初始身份验证时将令牌发送回客户端.
我正在尝试使用魔术字符串开始,所以我有这个代码:
RegisterRoutes(GlobalConfiguration.Configuration.Routes);
var builder = new SecurityTokenBuilder();
var jwtHandler = new JwtAuthenticationMessageHandler
{
AllowedAudience = "http://xxxx.com",
Issuer = "corp",
SigningToken = builder.CreateFromKey(Convert.ToBase64String(new byte[]{4,2,2,6}))
};
GlobalConfiguration.Configuration.MessageHandlers.Add(jwtHandler);
Run Code Online (Sandbox Code Playgroud)
但我不确定最初是如何回到客户端的.我想我理解如何在客户端上处理这个问题,但是如果你还可以展示这种交互的Angular方面,那么也可以获得奖励积分.
Mic*_*ael 21
我最终不得不从几个不同的地方获取信息来创建一个适合我的解决方案(实际上,生产可行的解决方案的开始 - 但它的工作原理!)
我摆脱了JwtAuthForWebAPI(尽管我从它那里借了一块来允许没有Authorization标头的请求流到没有[Authorize]保护的WebAPI Controller方法).
相反,我正在使用Microsoft的JWT库(来自NuGet 的Microsoft .NET Framework的JSON Web令牌处理程序).
在我的身份验证方法中,在进行实际身份验证之后,我创建了令牌的字符串版本并将其与经过身份验证的名称(在这种情况下传递给我的用户名相同)和实际上可能的角色一起传回在身份验证期间派生.
这是方法:
[HttpPost]
public LoginResult PostSignIn([FromBody] Credentials credentials)
{
var auth = new LoginResult() { Authenticated = false };
if (TryLogon(credentials.UserName, credentials.Password))
{
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, credentials.UserName),
new Claim(ClaimTypes.Role, "Admin")
}),
AppliesToAddress = ConfigurationManager.AppSettings["JwtAllowedAudience"],
TokenIssuerName = ConfigurationManager.AppSettings["JwtValidIssuer"],
SigningCredentials = new SigningCredentials(new
InMemorySymmetricSecurityKey(JwtTokenValidationHandler.SymmetricKey),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256")
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
auth.Token = tokenString;
auth.Authenticated = true;
}
return auth;
}
Run Code Online (Sandbox Code Playgroud)
UPDATE
有一个关于在后续请求中处理令牌的问题.我所做的是创建一个DelegatingHandler来尝试读取/解码令牌,然后创建一个Principal并将其设置为Thread.CurrentPrincipal和HttpContext.Current.User(您需要将它设置为两者).最后,我用适当的访问限制来装饰控制器方法.
这是DelegatingHandler的主要内容:
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpStatusCode statusCode;
string token;
var authHeader = request.Headers.Authorization;
if (authHeader == null)
{
// missing authorization header
return base.SendAsync(request, cancellationToken);
}
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode));
}
try
{
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters =
new TokenValidationParameters()
{
AllowedAudience = ConfigurationManager.AppSettings["JwtAllowedAudience"],
ValidIssuer = ConfigurationManager.AppSettings["JwtValidIssuer"],
SigningToken = new BinarySecretSecurityToken(SymmetricKey)
};
IPrincipal principal = tokenHandler.ValidateToken(token, validationParameters);
Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal;
return base.SendAsync(request, cancellationToken);
}
catch (SecurityTokenValidationException e)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (Exception)
{
statusCode = HttpStatusCode.InternalServerError;
}
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode));
}
Run Code Online (Sandbox Code Playgroud)
不要忘记将其添加到MessageHandlers管道中:
public static void Start()
{
GlobalConfiguration.Configuration.MessageHandlers.Add(new JwtTokenValidationHandler());
}
Run Code Online (Sandbox Code Playgroud)
最后,装饰你的控制器方法:
[Authorize(Roles = "OneRoleHere")]
[GET("/api/admin/settings/product/allorgs")]
[HttpGet]
public List<Org> GetAllOrganizations()
{
return QueryableDependencies.GetMergedOrganizations().ToList();
}
[Authorize(Roles = "ADifferentRoleHere")]
[GET("/api/admin/settings/product/allorgswithapproval")]
[HttpGet]
public List<ApprovableOrg> GetAllOrganizationsWithApproval()
{
return QueryableDependencies.GetMergedOrganizationsWithApproval().ToList();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11965 次 |
| 最近记录: |