64

我创建了一个 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"?如果没有,我怎样才能在基于 API 的 API 中获取用户access_token


编辑:

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

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

之后,我像这样访问控制器内的 GUID:User.Identity.Name

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

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

4

3 回答 3

98

您可以根据需要添加任意数量的声明。
您可以添加标准声明集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、bearer tokens 和 web api 的信息,这里有一个非常好的教程这篇文章将帮助你掌握Authorization ServerResource Server背后的所有概念。

更新

您可以在此处找到一个工作示例。这是一个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);
}

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

于 2014-10-14T20:22:29.700 回答
45

我的建议是不要在不需要时向令牌添加额外的声明,因为这会增加令牌的大小,并且您将继续在每个请求中发送它。正如 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);
    }

您可以在此处查看我的仓库以获取完整示例。希望它会有所帮助。

于 2014-10-17T23:08:43.117 回答
0

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

ticket.Properties.Dictionary.Add(new KeyValuePair<string, string>("Tag", "Data")); // Or whatever data you want to add
于 2021-11-13T12:49:53.700 回答