2015-07-19 82 views
2

我将确认电子邮件功能添加到我的ASP.NET WebAPI项目。服务器可以发送电子邮件,但是,确认链接始终返回“无效标记”。确认电子邮件得到无效令牌

我查了一些理由,在这里指出 http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/ 但似乎他们都不是根本原因

下面是我的代码:

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

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("[email protected]"); 
     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("[email protected]", "mypassword!"); 
     smtpClient.Credentials = credentials; 
     smtpClient.EnableSsl = true; 
     smtpClient.Send(msg); 
    } 
} 

and 2 MachineKey class

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

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

请告诉我我在哪里出问题

回答

0

我知道这是一个古老的线程。但我虽然增加了答案,因为它可以帮助其他人。

您正在使用下面的代码

string callbackUrl = urlHelper.Action(
        "ConfirmEmail", 
        "Account", 
        newRouteValues, 
        HttpContext.Current.Request.Url.Scheme 
        ); 

UrlHelper.Action已经做URL编码为你在最新版本的MVC。因此,在您的代码中,您正在执行两次编码(一个在Register内部,另一个在GetCallBackUrl内部,使用urlHelper.Action),这就是为什么您会收到无效令牌错误。