AspNet.Identit 2.1.0 ConfirmEmailAsync始终返回无效令牌

时间:2015-02-26 18:53:20

标签: c# asp.net-identity asp.net-web-api2

我正在尝试确认电子邮件,但每次收到无效令牌! 我从angulaJS应用程序调用API http://www.codeproject.com/Articles/784106/AngularJS-Token-Authentication-using-ASP-NET-Web-A

 // GET: /Account/ConfirmEmail
    [System.Web.Http.HttpGet]
    [System.Web.Http.AllowAnonymous]
    [System.Web.Http.Route("ConfirmEmail")]
    public async Task<IHttpActionResult> ConfirmEmail(string userId, string code)
    {
        var newcode = HttpContext.Current.Server.UrlDecode(code);

        if (userId == null || code == null)
        {
            return BadRequest(ModelState);
        }
        var result = await UserManager.ConfirmEmailAsync(userId, newcode);
        if (result.Succeeded) {
            return Ok(result.Succeeded);
        }
        return GetErrorResult(result);
    }

我要求2个地方的令牌

账户/注册中的

1              var result = await UserManager.CreateAsync(user,model.Password);

        if (result.Succeeded)
        {
         //   await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

            // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
            // Send an email with this link

            string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");


            return Ok(result.Succeeded);
        }
            return GetErrorResult(result);
        }

和另一个在ResendEmail中。

        [System.Web.Http.HttpGet]
    [System.Web.Http.Route("ResendEmail")]
    public async Task<IHttpActionResult> ResendEmail(string email)
    {
        if (ModelState.IsValid)
        {
            var user = await UserManager.FindByNameAsync(ActiveMember.Email);

            if (user.Email == email)
            {

                var callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your Email");

            }
            return Ok();
        }
        // If we got this far, something failed, redisplay form
        return BadRequest(ModelState);
    }

SendEmailConfirmationTokenAsync Helper

        private async Task<string> SendEmailConfirmationTokenAsync(string userId, string subject)
    {
        string host = Request.RequestUri.Host.ToLower();

        string code = await UserManager.GenerateEmailConfirmationTokenAsync(userId);
        string callbackUrl = host + "/#/account/ConfirmEmail?userId=" + userId + "&code=" + HttpContext.Current.Server.UrlEncode(code);
        await UserManager.SendEmailAsync(userId, subject, "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a><p>" + userId + "<p>" + code + "<p>" + callbackUrl);


        return callbackUrl;
    }

IdentityCinfig只有

var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider =
                new DataProtectorTokenProvider<Member>(dataProtectionProvider.Create("Identity"));
           // manager.UserTokenProvider = new EmailTokenProvider<Member, string>();
        }

这是我出错了吗?

感谢您的帮助。

2 个答案:

答案 0 :(得分:8)

我需要对url进行编码并且HttpUtilitu.UrlEncode无效,它用空格替换了字符+,导致令牌无效。

我有两个辅助方法

public static string Base64ForUrlEncode(string str)
{
    var encbuff = Encoding.UTF8.GetBytes(str);
    return HttpServerUtility.UrlTokenEncode(encbuff);
}

public static string Base64ForUrlDecode(string str)
{
   var decbuff = HttpServerUtility.UrlTokenDecode(str);
   return decbuff != null ? Encoding.UTF8.GetString(decbuff) : null;
}

使用

注册行动

var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
            var callbackUrl = string.Format("{0}/#confirm-email?userId={1}&code={2}", "your-web-url", user.Id.ToString(), StringHelper.Base64ForUrlEncode(code));

和ConfirmEmail操作

var result = await UserManager.ConfirmEmailAsync(userId.ConvertToGuid(), StringHelper.Base64ForUrlDecode(code));

答案 1 :(得分:0)

UrlTokenEncode在.Net Core中不可用。我已将@Labi's answer改成字符串扩展名,并包括 UrlTokenEncode种方法。

用法:

var code = (await _userManager.GenerateEmailConfirmationTokenAsync(user)).Base64ForUrlEncode();
public static class StringExtensions
{
    public static string Base64ForUrlEncode(this string str)
    {
        var buffer = Encoding.UTF8.GetBytes(str);
        return UrlTokenEncode(buffer);
    }

    public static string Base64ForUrlDecode(this string str)
    {
        var buffer = UrlTokenDecode(str);
        return buffer != null ? Encoding.UTF8.GetString(buffer) : null;
    }

    private static string UrlTokenEncode(byte[] input)
    {
        if (input == null)
            throw new ArgumentNullException(nameof(input));
        if (input.Length < 1)
            return string.Empty;

        ////////////////////////////////////////////////////////
        // Step 1: Do a Base64 encoding
        var base64String = Convert.ToBase64String(input);
        if (base64String == null)
            return null;

        int endPosition;
        ////////////////////////////////////////////////////////
        // Step 2: Find how many padding chars are present in the end
        for (endPosition = base64String.Length; endPosition > 0; endPosition--)
        {
            if (base64String[endPosition - 1] != '=') // Found a non-padding char!
            {
                break; // Stop here
            }
        }

        ////////////////////////////////////////////////////////
        // Step 3: Create char array to store all non-padding chars,
        //      plus a char to indicate how many padding chars are needed
        var base64Chars = new char[endPosition + 1];
        base64Chars[endPosition] = (char)('0' + base64String.Length - endPosition); // Store a char at the end, to indicate how many padding chars are needed

        ////////////////////////////////////////////////////////
        // Step 3: Copy in the other chars. Transform the "+" to "-", and "/" to "_"
        for (var i = 0; i < endPosition; i++)
        {
            var character = base64String[i];

            switch (character)
            {
                case '+':
                    base64Chars[i] = '-';
                    break;

                case '/':
                    base64Chars[i] = '_';
                    break;

                case '=':
                    Debug.Assert(false);
                    base64Chars[i] = character;
                    break;

                default:
                    base64Chars[i] = character;
                    break;
            }
        }
        return new string(base64Chars);
    }

    private static byte[] UrlTokenDecode(string input)
    {
        if (input == null)
            throw new ArgumentNullException(nameof(input));

        var inputLength = input.Length;
        if (inputLength < 1)
            return new byte[0];

        ///////////////////////////////////////////////////////////////////
        // Step 1: Calculate the number of padding chars to append to this string.
        //         The number of padding chars to append is stored in the last char of the string.
        var paddingCharacters = input[inputLength - 1] - '0';
        if (paddingCharacters < 0 || paddingCharacters > 10)
            return null;


        ///////////////////////////////////////////////////////////////////
        // Step 2: Create array to store the chars (not including the last char)
        //          and the padding chars
        var base64Chars = new char[inputLength - 1 + paddingCharacters];


        ////////////////////////////////////////////////////////
        // Step 3: Copy in the chars. Transform the "-" to "+", and "*" to "/"
        for (var i = 0; i < inputLength - 1; i++)
        {
            var character = input[i];

            switch (character)
            {
                case '-':
                    base64Chars[i] = '+';
                    break;

                case '_':
                    base64Chars[i] = '/';
                    break;

                default:
                    base64Chars[i] = character;
                    break;
            }
        }

        ////////////////////////////////////////////////////////
        // Step 4: Add padding chars
        for (var i = inputLength - 1; i < base64Chars.Length; i++)
        {
            base64Chars[i] = '=';
        }

        // Do the actual conversion
        return Convert.FromBase64CharArray(base64Chars, 0, base64Chars.Length);
    }
}