有many resources描述了使用.Net Web API在C#中创建和使用JWT的实现。但是,我正在努力使我当前的系统适应所列出的任何教程。
我到目前为止一直在发送我的JWT令牌作为查询字符串的一部分,如下所示:
... / API /用户?JWT = aladsfjknasdfnjkladfskjlnajknjknfdsalnjksdfnjldf
我的路线看起来像这样:
public async Task<IHttpActionResult> GetUsers(string jwt)
{
var userValidationResult = await Utility.ValidateUser(jwt);
if (!userValidationResult.Validated)
{
return Unauthorized();
}
...
}
您可以在下面查看该验证用户方法的内容。请注意,我实际上是通过将JWT发送到其他服务器进行身份验证来验证JWT。
public class UserValidationResult
{
public bool Validated { get; set; }
public string Email { get; set; }
public List<string> Roles { get; set; }
}
public static Task<UserValidationResult> ValidateUser(string jwt)
{
var taskCompletionSource = new TaskCompletionSource<UserValidationResult>();
var authenticationRoute = "http://authserver:5000/authenticate?jwt=" +jwt;
var authenticationClient = new RestClient(authenticationRoute);
var authenticationRequest = new RestRequest(Method.GET);
authenticationClient.ExecuteAsync(authenticationRequest, authenticationResponse =>
{
var authenticationResponseInJson = JObject.Parse(authenticationResponse.Content.ToString());
var payload = JObject.Parse(authenticationResponseInJson["payload"].ToString());
taskCompletionSource.SetResult(new UserValidationResult()
{
Validated = bool.Parse(authenticationResponseInJson["success"].ToString()),
Email = ...
Roles = ...
});
});
return taskCompletionSource.Task;
}
这很有效。但是我更喜欢使用你在所有OWIN / Katana教程中看到的漂亮的[Authorize]
属性。有没有办法让Owin Middleware能够像现在一样验证jwt令牌,就像现在一样,除非使用Authorize属性?
修改
所以我实现了以下中间件并在我的启动类中使用它:
public class AuthorizationMiddleware : OwinMiddleware
{
private OwinMiddleware _next;
public AuthorizationMiddleware(OwinMiddleware next):base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
var jwt = context.Request.Query.Get("jwt");
if (jwt != null)
{
var userValidationResult = await Utility.ValidateUser(jwt);
if (userValidationResult.Validated)
{
var jwtoken = new JwtSecurityToken(jwt);
var identity = new ClaimsIdentity("jwt");
//foreach (var role in userValidationResult.Roles)
// identity.AddClaim(new Claim(ClaimTypes.Role, role));
identity.AddClaim(new Claim(ClaimTypes.Email, userValidationResult.Email));
context.Request.User = new ClaimsPrincipal(identity);
}
}
await _next.Invoke(context);
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use<AuthorizationMiddleware>();
var config = new HttpConfiguration();
app.UseWebApi(config);
}
}
但是,我用Authorize
属性修饰的路径似乎都没有触及invoke方法中的任何断点。我总是找回未经授权的401.为什么会这样?
答案 0 :(得分:2)
您可以在OWIN管道上实现基本中间件。简单的东西可以满足您的要求:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(async (ctx, next) =>
{
var jwt = ctx.Request.Query.Get("jwt");
if (jwt != null)
{
var userValidationResult = await Utility.ValidateUser(jwt);
if (userValidationResult.Validated)
{
var identity = new ClaimsIdentity("jwt");
foreach(var role in userValidationResult.Roles)
identity.AddClaim(new Claim(ClaimTypes.Role, role));
identity.AddClaim(new Claim(ClaimTypes.Email, userValidationResult.Email));
//etc... add every claim
ctx.Request.User = new ClaimsPrincipal(identity);
}
}
await next.Invoke();
});
var config = new HttpConfiguration();
app.UseWebApi(config);
//etc...
}
}
这只是一个存根,您可能需要扩展代码才能使其在您的特定环境中运行。
像这样的中间件将设置Request.User
,然后由其他中间件(包括Web API授权过滤器)使用。然后,您可以使用[Authorize()]
属性自由装饰控制器/操作。
如果您需要更灵活的内容,我建议您详细了解how to implement an authentication middleware。
来自Brock Allen的资源也可以帮助您实现这样的实现:OWIN Authentication Middleware Architecture。