首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >确认电子邮件收到的令牌无效

确认电子邮件收到的令牌无效
EN

Stack Overflow用户
提问于 2015-07-20 01:43:47
回答 1查看 445关注 0票数 3

我正在向我的ASP.NET WebAPI项目添加确认电子邮件功能。服务器可以正常发送电子邮件,但是确认链接总是返回“无效令牌”。

我检查了这里指出的一些原因,http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/,但似乎没有一个是根本原因

下面是我的代码:

代码语言:javascript
复制
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        IdentityResult result;           
            result = await UserManager.CreateAsync(user, model.Password);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }
            try
            {
                await userManager.AddToRoleAsync(user.Id, "Player");

                //Generate email confirmation token                                        
                //var provider = new DpapiDataProtectionProvider("GSEP");
                var provider = new MachineKeyProtectionProvider();
                userManager.UserTokenProvider = new DataProtectorTokenProvider<GSEPUser>(provider.Create("EmailConfirmation"));
                var code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
                code = System.Web.HttpUtility.UrlEncode(code);

                EmailHelper emailHelper = new EmailHelper();
                string callBackUrl = emailHelper.GetCallBackUrl(user, code);
                EmailMessage message = new EmailMessage();
                message.Body = callBackUrl;
                message.Destination = user.Email;
                message.Subject = "GSEP Account confirmation";
                emailHelper.sendMail(message);
            }
            catch (Exception e)
            {
                return Ok(GSEPWebAPI.App_Start.Constants.ErrorException(e));
            }         
    }

现在是EmailHelper

代码语言:javascript
复制
public class EmailHelper
{
    public string GetCallBackUrl(GSEPUser user, string code)
    {

        var newRouteValues = new RouteValueDictionary(new { userId = user.Id, code = code });

        newRouteValues.Add("httproute", true);            
        UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext, RouteTable.Routes);
        string callbackUrl = urlHelper.Action(
                    "ConfirmEmail",
                    "Account",
                    newRouteValues,
                    HttpContext.Current.Request.Url.Scheme
                    );
        return callbackUrl;
    }

    public void sendMail(EmailMessage message)
    {
        #region formatter
        string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
        string html = "Please confirm your account by clicking this link: <a href=\"" + message.Body + "\">link</a><br/>";

        html += HttpUtility.HtmlEncode(@"Or click on the copy the following link on the browser:" + message.Body);
        #endregion

        MailMessage msg = new MailMessage();
        msg.From = new MailAddress("myemail@example.com");
        msg.To.Add(new MailAddress(message.Destination));
        msg.Subject = message.Subject;
        msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
        msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));

        SmtpClient smtpClient = new SmtpClient("smtp-mail.outlook.com", Convert.ToInt32(587));
        System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("myemail@example.com", "mypassword!");
        smtpClient.Credentials = credentials;
        smtpClient.EnableSsl = true;
        smtpClient.Send(msg);
    }
}

和2个MachineKey类

代码语言:javascript
复制
public class MachineKeyProtectionProvider : IDataProtectionProvider
{
    public IDataProtector Create(params string[] purposes)
    {
        return new MachineKeyDataProtector(purposes);
    }
}

public class MachineKeyDataProtector : IDataProtector
{
    private readonly string[] _purposes;

    public MachineKeyDataProtector(string[] purposes)
    {
        _purposes = purposes;
    }

    public byte[] Protect(byte[] userData)
    {
        return MachineKey.Protect(userData, _purposes);
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        return MachineKey.Unprotect(protectedData, _purposes);
    }
}

正如一些说明所指出的,我还在Web.config中添加了machineKey标签。最后是我的确认电子邮件API

代码语言:javascript
复制
    [AllowAnonymous]
    [HttpGet]
    public async Task<IHttpActionResult> ConfirmEmail(string userId, string code)
    {
        if (userId == null || code == null)
        {
            return Ok("Confirm error");
        }
        IdentityResult result;
        try
        {
            result = await UserManager.ConfirmEmailAsync(userId, code);
        }
        catch (InvalidOperationException ioe)
        {
            // ConfirmEmailAsync throws when the userId is not found.
            return Ok("UserID not found");
        }

        if (result.Succeeded)
        {
            return Ok("Confirmation succesfully");
        }
        else
        {
            return Ok(result.Errors);
        }
    }

请告诉我我哪里错了

EN

回答 1

Stack Overflow用户

发布于 2017-09-27 20:17:00

我知道这是一个古老的主题。但我想加上答案,因为它可以帮助其他人。

您正在使用以下代码

代码语言:javascript
复制
string callbackUrl = urlHelper.Action(
                    "ConfirmEmail",
                    "Account",
                    newRouteValues,
                    HttpContext.Current.Request.Url.Scheme
                    );

在最新的MVC版本中,UrlHelper.Action 已经为你做了url编码。因此,在这里的代码中,您进行了两次编码(一次在Register中,另一次在GetCallBackUrl中使用urlHelper.Action),这就是为什么会出现invalid token错误的原因。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31504080

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档