【问题标题】:Return more info to the client using OAuth Bearer Tokens Generation and Owin in WebApi在 WebApi 中使用 OAuth Bearer Tokens Generation 和 Owin 向客户端返回更多信息
【发布时间】:2014-12-09 00:36:23
【问题描述】:

我创建了一个 WebApi 和一个 Cordova 应用程序。 我正在使用 HTTP 请求在 Cordova 应用程序和 WebAPI 之间进行通信。 在 WebAPI 中,我实现了 OAuth Bearer Token Generation。

public void ConfigureOAuth(IAppBuilder app)
    {
        var oAuthServerOptions = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new SimpleAuthorizationServerProvider(new UserService(new Repository<User>(new RabbitApiObjectContext()), new EncryptionService()))
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(oAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

    }

这是在SimpleAuthorizationServerProvider 实现中

 public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
       context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        // A little hack. context.UserName contains the email
        var user = await _userService.GetUserByEmailAndPassword(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "Wrong email or password.");
            return;
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("sub", context.UserName));
        identity.AddClaim(new Claim("role", "user"));

        context.Validated(identity);
    }

从 Cordova 应用成功登录 API 请求后,我收到以下 JSON

{"access_token":"some token","token_type":"bearer","expires_in":86399}

问题是,我需要有关用户的更多信息。例如,我在数据库中有一个 UserGuid 字段,我想在登录成功时将其发送到 Cordova 应用程序,并稍后在其他请求中使用它。除了"access_token", "token_type""expires_in" 之外,我可以包含其他信息以返回给客户吗?如果没有,如何根据access_token在API中获取用户?


编辑:

我认为我找到了解决方法。 我在GrantResourceOwnerCredentials中添加了以下代码

identity.AddClaim(new Claim(ClaimTypes.Name, user.UserGuid.ToString()));

然后,我访问控制器内的 GUID,如下所示:User.Identity.Name

我还可以添加自定义名称 identity.AddClaim(new Claim("guid", user.UserGuid.ToString())); 的 guid

我仍然很想知道是否有办法使用不记名令牌 JSON 向客户端返回更多数据。

【问题讨论】:

    标签: c# authentication owin asp.net-web-api2 bearer-token


    【解决方案1】:

    您可以根据需要添加任意数量的声明。
    您可以添加来自 System.Security.Claims 的标准声明集或创建自己的声明。
    声明将在您的令牌中加密,因此只能从资源服务器访问它们。

    如果您希望您的客户端能够读取令牌的扩展属性,您还有另一个选择:AuthenticationProperties

    假设您想添加一些内容,以便您的客户可以访问。这就是要走的路:

    var props = new AuthenticationProperties(new Dictionary<string, string>
    {
        { 
            "surname", "Smith"
        },
        { 
            "age", "20"
        },
        { 
        "gender", "Male"
        }
    });
    

    现在您可以使用上面添加的属性创建票证:

    var ticket = new AuthenticationTicket(identity, props);
    context.Validated(ticket);
    

    这是您的客户将获取的结果:

    .expires: "Tue, 14 Oct 2014 20:42:52 GMT"
    .issued: "Tue, 14 Oct 2014 20:12:52 GMT"
    access_token: "blahblahblah"
    expires_in: 1799
    age: "20"
    gender: "Male"
    surname: "Smith"
    token_type: "bearer"
    

    另一方面,如果您添加声明,您将能够在 API 控制器的资源服务器中读取它们:

    public IHttpActionResult Get()
    {
        ClaimsPrincipal principal = Request.GetRequestContext().Principal as ClaimsPrincipal;
    
        return Ok();
    }
    

    您的ClaimsPrincipal 将包含您在此处添加的新声明guid

    identity.AddClaim(new Claim("guid", user.UserGuid.ToString()));
    

    如果你想了解更多关于 owin、不记名令牌和 web api 的信息,有一个非常好的教程 here 和这个 article 将帮助你掌握 Authorization Server 背后的所有概念strong>资源服务器

    更新

    您可以找到一个工作示例here。这是一个 Web Api + Owin 自托管。
    这里不涉及数据库。 客户端是一个控制台应用程序(还有一个 html + JavaScript 示例),它调用 Web Api 传递凭据。

    正如Taiseer 所建议的,您需要覆盖TokenEndpoint

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    {
        foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
        {
            context.AdditionalResponseParameters.Add(property.Key, property.Value);
        }
    
        return Task.FromResult<object>(null);
    }
    

    从解决方案 -> 属性中启用“多个启动项目”,您可以立即运行它。

    【讨论】:

    • 感谢您的回复。当我写 API 时,我把完全相同的文章发红了,我什至下载了代码并通过了它。所以我尝试使用AuthenticationProperties,但结果是一样的。在客户端,我仍然只收到access_tokentoken_typeexpires_in 属性。
    • 我已经在那个项目中测试了我的解决方案并且它可以工作。您是否使用像 fiddler 这样的嗅探器来查看发生了什么?
    • 是的。我在用Fiddler,也在调试API,结果还是一样。
    • 这将不起作用,除非您从 Taiseer 的答案中覆盖公共覆盖 Task TokenEndpoint(OAuthTokenEndpointContext context)
    • @Ers:是的,你是对的。忘了提......但它在我的回购中。感谢您的反对。
    【解决方案2】:

    如果不需要,我的建议是不要向令牌添加额外的声明,因为这会增加令牌的大小,并且您将继续在每个请求中发送它。 正如 LeftyX 建议的那样,将它们添加为属性,但确保在成功获取令牌时覆盖 TokenEndPoint 方法以获取这些属性作为响应,如果没有此端点,属性将不会在响应中返回。

     public override Task TokenEndpoint(OAuthTokenEndpointContext context)
        {
            foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
            {
                context.AdditionalResponseParameters.Add(property.Key, property.Value);
            }
    
            return Task.FromResult<object>(null);
        }
    

    您可以在此处查看my repo 以获取完整示例。希望它会有所帮助。

    【讨论】:

    • @TaiseerJoudeh 你知道我是否可以将字符串数组作为属性之一吗?我需要发送权限列表
    • 到今天为止,ASOS 用于 Asp.Net Core,情况似乎发生了一些变化。 context.Properties.Dictionarycontext.Ticket.Properties.Items,但我找不到 context.AdditionalResponseParameters 等价物。有人知道吗?
    • 没关系,被 ASOS 作者链接到this
    • @TaiseerJoudeh 是否可以包含其他用户模型属性,例如 user.birthday?我在上下文中看到的唯一用户属性是 context.username。 ¿如何包含其他用户属性?
    • @AminM 如果您需要 identity.AddClaim(new Claim("Family", "Family name value"));,您可以手动将它们添加为声明
    【解决方案3】:

    GrantResourceOwnerCredentials 函数中,您可以使用以下行向响应添加更多信息。

    ticket.Properties.Dictionary.Add(new KeyValuePair<string, string>("Tag", "Data")); // Or whatever data you want to add
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-19
      • 2014-07-07
      • 1970-01-01
      • 2015-09-21
      • 2016-10-10
      • 2014-07-07
      • 2014-10-18
      • 1970-01-01
      相关资源
      最近更新 更多