手动授予访问令牌MVC Web API

时间:2015-06-26 19:58:40

标签: asp.net-mvc model-view-controller asp.net-web-api

我允许用户从应用程序注册MVC Web API。该应用程序通过电子邮件,但没有密我添加了用户并分配了一个随机密码,我将其邮寄给用户。

我不希望该应用对api进行两次调用以获取令牌。 因此,对于此请求,我想返回/token端点返回的oauth令牌。

我正在尝试此操作,但此请求中的令牌会被拒绝访问。 我在这里错过了什么?如果有更好的方式,非常感谢。

Web API具有Web API模板等默认配置。什么都不习惯。我想保持这种方式。

        ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
        Claim providerKeyClaim = new Claim(ClaimTypes.Email, model.Email, ClaimValueTypes.String, "DrySignup", "DrySignup");

        ExternalLoginData externalLogin = new ExternalLoginData
        {
            LoginProvider = providerKeyClaim.Issuer,
            ProviderKey = providerKeyClaim.Value,
            UserName = identity.FindFirstValue(ClaimTypes.Email)
        };

        var info = new ExternalLoginInfo()
        {
            DefaultUserName = model.Email,
            Login = new UserLoginInfo(providerKeyClaim.Issuer, externalLogin.ProviderKey)
        };

        result = await UserManager.AddLoginAsync(user.Id, info.Login);
        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        identity = await UserManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType);
        IEnumerable<Claim> claims = externalLogin.GetClaims();
        identity.AddClaims(claims);
        Authentication.SignIn(identity);

        AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
        var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
        ticket.Properties.IssuedUtc = currentUtc;
        ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromDays(365));
        var accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);
        Request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);



        // Create the response building a JSON object that mimics exactly the one issued by the default /Token endpoint
        JObject token = new JObject(
            new JProperty("userName", user.UserName),
            new JProperty("userId", user.Id),
            new JProperty("access_token", accessToken),
            new JProperty("token_type", "bearer"),
            new JProperty("expires_in", TimeSpan.FromDays(9999).TotalSeconds.ToString()),
            new JProperty("issued", currentUtc.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'")),
            new JProperty("expires", currentUtc.Add(TimeSpan.FromDays(365)).ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"))
        );
        return Ok(token);

2 个答案:

答案 0 :(得分:13)

这很有效。

ClaimsIdentity oAuthIdentity = new ClaimsIdentity(Startup.OAuthOptions.AuthenticationType);

oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
oAuthIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));

AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());

DateTime currentUtc = DateTime.UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromDays(365));

string accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);
Request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);



// Create the response building a JSON object that mimics exactly the one issued by the default /Token endpoint
JObject token = new JObject(
    new JProperty("userName", user.UserName),
    new JProperty("userId", user.Id),
    new JProperty("access_token", accessToken),
    new JProperty("token_type", "bearer"),
    new JProperty("expires_in", TimeSpan.FromDays(365).TotalSeconds.ToString()),
    new JProperty("issued", currentUtc.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'")),
    new JProperty("expires", currentUtc.Add(TimeSpan.FromDays(365)).ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"))
);

return Ok(token);

答案 1 :(得分:2)

对您的问题的简短回答是,您不能以这种方式发出令牌并使用内置的OAuthProvider。

通过将此功能设置为OAuthServerOptions中的response_type=token&client_id=something&redirect_uri=/index.html,您仍然可以满足您的需求。

如果你这样做,虽然你必须发送http://example.com/index.html/#access_token={long token string here}&token_type=bearer&expires_in=1209600查询参数作为请求的一部分,然后你将得到的是一个302,访问令牌作为网址的一部分。就像是: ApplicationUser user = await UserManager.FindByEmailAsync("email@example.com"); ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager, OAuthDefaults.AuthenticationType); AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName); Authentication.SignIn(properties, oAuthIdentity); return Ok();

然后在你的控制器功能中你的代码看起来像这样

GranCustomExtension

您的第二个选择是实施自定义授权类型。这将允许您调用/ token服务并创建一个帐户。在您的OAuthProvider类上,您需要覆盖public override async Task GrantCustomExtension(OAuthGrantCustomExtensionContext context) { var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); var email = context.Parameters["Email"]; var createUser = new ApplicationUser() { UserName = email, Email = email }; IdentityResult result = await userManager.CreateAsync(createUser, "Som3R@ndomPassword"); if (!result.Succeeded) { return; } ApplicationUser user = await userManager.FindByEmailAsync(email); ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType); AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName); AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); context.Validated(ticket); } 函数。

grant_type=create&Email=test3%40example.com

然后,您就可以使用带有此类password之类的表单urlencoded请求发布到/ token,并且您的响应与您grant_type MethodInfo method = typeof(Example) .GetMethods().First(mi => mi.Name == "DoSomething" && mi.IsGenericMethod); 的响应相同

相关问题