从注册请求中返回访问令牌的最佳方法是哪种OpenIddict C#dotnet core 2.2

时间:2019-03-21 13:47:20

标签: .net-core openiddict

我正在研究Web API,我正在寻找注册后生成访问令牌的最佳方法。

方案::用户成功创建用户正在执行的操作后,便从移动应用程序(Ios,Android)提交了创建帐户的请求,并传递了参数的名字,姓氏,密码以及电子邮件或电话正在创建登录请求并返回响应。

问题:有什么最佳方法吗?使用这种方法,我无法通过XUnit对其进行测试,因为它能够创建用户,但是在尝试登录时出现错误

    [HttpPost, Route("signup")]
    [ProducesErrorResponseType(typeof(Error))]
    [ProducesResponseType(typeof(AccessTokenResponse), (int)HttpStatusCode.OK)]
    [AllowAnonymous]
    public async Task<IActionResult> Register([FromBody]RegistrationDto model)
    {
        ValidatePassword(model.Password, nameof(model.Password));
        if (!ModelState.IsValid)
        {
            return InoperableResult(ModelState);
        }

        var appUsr = _mapper.Map<AppUser>(model);

        if (Utilities.IsValidEmail(model.Identifier))
        {
            var isEmailAlreadyRegistered = await _customUserManager.IsEmailRegistered(model.Identifier);
            if (isEmailAlreadyRegistered)
            {
                var er = new Error(ErrorCodes.RegistrationFailure, "Failed to register user.");
                er.AddDetailError("DuplicateEmailAddress", "Email address is already registered.");
                return InoperableResult(er);
            }
            appUsr.Email = model.Identifier;
            appUsr.UserName = model.Identifier;
        }
        else
        {
            var isPhoneAlreadyRegistered = await _customUserManager.IsPhoneRegistered(model.Identifier);
            if (isPhoneAlreadyRegistered)
            {
                var er = new Error(ErrorCodes.RegistrationFailure, "Failed to register user.");
                er.AddDetailError("DuplicatePhoneNumber", "Phone number is already registered.");
                return InoperableResult(er);
            }
            appUsr.PhoneNumber = model.Identifier;
            appUsr.UserName = model.Identifier;
        }
        appUsr.IsActive = true;
        IdentityResult result = await _userManager.CreateAsync(appUsr, model.Password);

        if (!result.Succeeded)
            return InoperableResult(ErrorCodes.RegistrationFailure, "Failed to register user.", result);

        if (appUsr.Email.HasValue())
        {
            await _notifier.SendWelcomeEmail(appUsr);
            await _notifier.SendVerificationCode(appUsr, CustomUserManager.ConfirmEmailTokenPurpose, NotificationRoute.Email);
        }

        if (appUsr.PhoneNumber.HasValue())
            await _notifier.SendVerificationCode(appUsr, CustomUserManager.ConfirmPhoneTokenPurpose, NotificationRoute.SMS);

        try
        {
            var json = await LoginAsync(appUsr.UserName, model.Password);
            if (!string.IsNullOrEmpty(json))
            {
                return new OkObjectResult(json);
            }


            // Getting BaseUrl and will use for invoking sign in action to get the tokens
            string BaseUrl = $"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase}";
            var uri = String.Format("{0}/api/connect/token", BaseUrl);
            // prepare form url encoded object for sign in request
            var formData = new FormUrlEncodedContent(new[] {
              new KeyValuePair<string, string>("username", appUsr.UserName),
              new KeyValuePair<string, string>("password", model.Password),
              new KeyValuePair<string, string>("grant_type", "password"),
              new KeyValuePair<string, string>("scope", "openid profile offline_access"),
            //  //new KeyValuePair<string, string>("resource", BaseUrl)
            //});

            var client = new HttpClient();

            var req = new HttpRequestMessage(HttpMethod.Post, uri) { Content = formData };
            var res = await client.SendAsync(req); // execute sign in requset after sucessfully account creation
            var responseString = await res.Content.ReadAsStringAsync();
            if (res.StatusCode == HttpStatusCode.OK)
            {
                return new OkObjectResult(responseString);
            }

        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message, ex);
        }
        return InoperableResult(ErrorCodes.LoginFailure, "User is created but failed to Sign in");
    }

登录

[HttpPost("~/api/connect/token")]
    [Consumes("application/x-www-form-urlencoded")]
    [ProducesResponseType(typeof(AccessTokenResponse), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> Exchange([FromBody]OpenIdConnectRequest request)
    {
        if (request.IsPasswordGrantType())
        {
            request.Username = request.Username.Replace(" ", "+");
            var user = await _customUserManager.FindByEmailOrPhone(request.Username);
            if (user == null)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "User not found.", HttpStatusCode.Unauthorized.ToInt());
            }

            // Ensure the user is active.
            if (!user.IsActive)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "The specified user account is disabled.",
                    HttpStatusCode.Unauthorized.ToInt());
            }

            // Validate the username/password parameters and ensure the account is not locked out.
            var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, true);

            // Ensure the user is not already locked out.
            if (result.IsLockedOut)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "The specified user account has been suspended.",
                    HttpStatusCode.Unauthorized.ToInt());
            }

            // Reject the token request if two-factor authentication has been enabled by the user.
            if (result.RequiresTwoFactor)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "Invalid login procedure.",
                        HttpStatusCode.Unauthorized.ToInt());
            }

            // Ensure the user is allowed to sign in.
            if (result.IsNotAllowed)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "The specified user is not allowed to sign in.",
                      HttpStatusCode.Unauthorized.ToInt());
            }

            if (!result.Succeeded)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "Please check that your email and password is correct.",
                     HttpStatusCode.Unauthorized.ToInt());
            }

            // Create a new authentication ticket.
            var ticket = await _customUserManager.CreateTicketAsync(request, user);
            return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
        }
        else if (request.IsRefreshTokenGrantType())
        {
            // Retrieve the claims principal stored in the refresh token.
            var info = await HttpContext.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);

            // Retrieve the user profile corresponding to the refresh token.
            // Note: if you want to automatically invalidate the refresh token
            // when the user password/roles change, use the following line instead:
            // var user = _signInManager.ValidateSecurityStampAsync(info.Principal);
            var user = await _userManager.GetUserAsync(info.Principal);
            if (user == null)
            {
                return InoperableResult(ErrorCodes.LoginFailure, "The refresh token is no longer valid.",
                    HttpStatusCode.Unauthorized.ToInt());
            }

            // Ensure the user is still allowed to sign in.
            if (!await _signInManager.CanSignInAsync(user))
            {
                return InoperableResult(ErrorCodes.LoginFailure, "The user is no longer allowed to sign in.",
                    HttpStatusCode.Unauthorized.ToInt());
            }

            // Create a new authentication ticket, but reuse the properties stored
            // in the refresh token, including the scopes originally granted.

            var ticket = await _customUserManager.CreateTicketAsync(request, user);
            return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
        }

        var er = new Error(ErrorCodes.LoginFailure, ResponseMessages.InvalidDataMsg);
        er.AddDetailError(OpenIdConnectConstants.Errors.InvalidGrant, "The specified grant type is not supported.");
        return InoperableResult(er);
    }

0 个答案:

没有答案