通过调用另一个服务来消耗JWT

时间:2016-05-06 02:00:20

标签: c# asp.net asp.net-web-api owin jwt

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.为什么会这样?

1 个答案:

答案 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