简体   繁体   English

手动授予访问令牌MVC Web API

[英]Granting access token manually MVC Web API

I am allowing user registration to MVC Web API from an App. 我允许用户从应用程序注册MVC Web API。 The app passes Email but no password. 该应用程序通过电子邮件,但没有密 I add the user and assign a random password which I mail to the user. 我添加用户并分配一个随机密码,我将其邮寄给用户。

I don't want the app to make two calls to api to get the token. 我不希望应用程序两次调用api来获取令牌。 So, to this request I want to return an oauth token which /token endpoint returns. 因此,对于此请求,我想返回/token端点返回的oauth令牌。

I was trying this but the token from this request gets Access Denied. 我正在尝试这个但是来自此请求的令牌会被拒绝访问。 What am I missing here? 我在这里错过了什么? If there is a better way, much appreciated. 如果有更好的方式,非常感谢。

Web API has the default configs like Web API Template. Web API具有Web API模板等默认配置。 Nothing custom. 什么都不习惯。 I would like to keep it this way. 我想保持这种方式。

        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);

This works. 这有效。

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);

The short answer to your problem, is you can't issue tokens that way and use the built in OAuthProvider. 对您的问题的简短回答是,您不能以这种方式发出令牌并使用内置的OAuthProvider。

You can still kind of what you want by setting this function as the AuthorizeEndpointPath in the OAuthServerOptions . 通过将此功能设置为OAuthServerOptionsAuthorizeEndpointPath ,您仍然可以实现所需的功能。

If you do that though you will have to send response_type=token&client_id=something&redirect_uri=/index.html query params as part of the request and then what you will get back is a 302 with the access token as part of the url. 如果你这样做,虽然你必须发送response_type=token&client_id=something&redirect_uri=/index.html查询params作为请求的一部分,然后你将得到的是一个302,其中访问令牌作为url的一部分。 Something like: http://example.com/index.html/#access_token={long token string here}&token_type=bearer&expires_in=1209600 类似于: http://example.com/index.html/#access_token={long token string here}&token_type=bearer&expires_in=1209600http://example.com/index.html/#access_token={long token string here}&token_type=bearer&expires_in=1209600

Then in you controller function your code would look something like this 然后在您的控制器功能中,您的代码看起来像这样

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();

Your second options would be to implement a custom grant type. 您的第二个选择是实现自定义授权类型。 This would allow you to call the /token service and create an account. 这将允许您调用/ token服务并创建一个帐户。 On you OAuthProvider class you would want to override the GranCustomExtension function. 在您的OAuthProvider类上,您可能希望覆盖GranCustomExtension函数。

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);
        }

Then you would be able to post to /token with a form-urlencoded request with something like this grant_type=create&Email=test3%40example.com and your response would be the same as if you did a password grant_type 然后,您可以使用带有此类grant_type=create&Email=test3%40example.com的form-urlencoded请求发布到/ token,您的响应将与您输入password grant_type

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM