mirror of
https://github.com/fergalmoran/podnoms.git
synced 2026-01-03 07:05:32 +00:00
Waiting for token reset
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
@@ -14,11 +16,14 @@ namespace PodNoms.Api.Controllers {
|
||||
public class AuthController : Controller {
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly IJwtFactory _jwtFactory;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly JwtIssuerOptions _jwtOptions;
|
||||
|
||||
public AuthController(UserManager<ApplicationUser> userManager, IJwtFactory jwtFactory, IOptions<JwtIssuerOptions> jwtOptions) {
|
||||
public AuthController(UserManager<ApplicationUser> userManager, IJwtFactory jwtFactory, IOptions<JwtIssuerOptions> jwtOptions,
|
||||
IEmailSender emailSender) {
|
||||
_userManager = userManager;
|
||||
_jwtFactory = jwtFactory;
|
||||
_emailSender = emailSender;
|
||||
_jwtOptions = jwtOptions.Value;
|
||||
}
|
||||
|
||||
@@ -34,7 +39,7 @@ namespace PodNoms.Api.Controllers {
|
||||
return BadRequest(Errors.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState));
|
||||
}
|
||||
|
||||
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, credentials.UserName, _jwtOptions,
|
||||
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, credentials.UserName, _jwtOptions,
|
||||
new JsonSerializerSettings { Formatting = Formatting.Indented });
|
||||
return new OkObjectResult(jwt);
|
||||
}
|
||||
@@ -51,12 +56,51 @@ namespace PodNoms.Api.Controllers {
|
||||
// check the credentials
|
||||
if (await _userManager.CheckPasswordAsync(userToVerify, password)) {
|
||||
await _userManager.UpdateAsync(userToVerify);
|
||||
|
||||
|
||||
return await Task.FromResult(_jwtFactory.GenerateClaimsIdentity(userName, userToVerify.Id));
|
||||
}
|
||||
|
||||
// Credentials are invalid, or account doesn't exist
|
||||
return await Task.FromResult<ClaimsIdentity>(null);
|
||||
}
|
||||
[HttpPost("reset")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> ForgotPassword([FromBody]ForgotPasswordViewModel model) {
|
||||
if (ModelState.IsValid) {
|
||||
var user = await _userManager.FindByNameAsync(model.Email);
|
||||
if (user == null) {
|
||||
// Don't reveal that the user does not exist or is not confirmed
|
||||
return BadRequest(model);
|
||||
}
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
|
||||
// Send an email with this link
|
||||
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
|
||||
"Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");
|
||||
return Ok(model);
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return BadRequest(model);
|
||||
}
|
||||
|
||||
[HttpPost("/reset")]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model) {
|
||||
if (!ModelState.IsValid) {
|
||||
return BadRequest("Unable to reset your password at this time");
|
||||
}
|
||||
var user = await _userManager.FindByNameAsync(model.Email);
|
||||
if (user == null) {
|
||||
return BadRequest("Unable to reset your password at this time");
|
||||
}
|
||||
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
|
||||
if (result.Succeeded) {
|
||||
return BadRequest();
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
server/Models/ViewModels/ForgotPasswordViewModel.cs
Normal file
9
server/Models/ViewModels/ForgotPasswordViewModel.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PodNoms.Api.Models.ViewModels {
|
||||
public class ForgotPasswordViewModel {
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
21
server/Models/ViewModels/ResetPasswordViewModel.cs
Normal file
21
server/Models/ViewModels/ResetPasswordViewModel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PodNoms.Api.Models.ViewModels {
|
||||
public class ResetPasswordViewModel {
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
17
server/Services/Auth/EmailSender.cs
Normal file
17
server/Services/Auth/EmailSender.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using PodNoms.Api.Services;
|
||||
|
||||
namespace PodNoms.Api.Services.Auth {
|
||||
public class EmailSender : IEmailSender {
|
||||
private readonly IMailSender _mailSender;
|
||||
|
||||
public EmailSender(IMailSender mailSender) {
|
||||
this._mailSender = mailSender;
|
||||
}
|
||||
|
||||
public async Task SendEmailAsync(string email, string subject, string htmlMessage) {
|
||||
await this._mailSender.SendEmail(email, subject, htmlMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,10 @@ namespace PodNoms.Api.Services {
|
||||
|
||||
public async Task<bool> SendEmail(string email, string subject, string message){
|
||||
using (var client = new HttpClient { BaseAddress = new Uri(_emailSettings.ApiBaseUri) }) {
|
||||
client.DefaultRequestHeaders.Authorization =
|
||||
client.DefaultRequestHeaders.Authorization =
|
||||
new AuthenticationHeaderValue("Basic",
|
||||
Convert.ToBase64String(Encoding.ASCII.GetBytes(_emailSettings.ApiKey)));
|
||||
|
||||
|
||||
_logger.LogInformation($"From: {_emailSettings.From}\nTo: {email}\nApi key: {_emailSettings.ApiKey}");
|
||||
|
||||
var content = new FormUrlEncodedContent(new[]
|
||||
@@ -37,7 +37,7 @@ namespace PodNoms.Api.Services {
|
||||
var result = await client.PostAsync(_emailSettings.RequestUri, content).ConfigureAwait(false);
|
||||
if (result.StatusCode == HttpStatusCode.OK)
|
||||
return true;
|
||||
|
||||
|
||||
_logger.LogError($"Error {result.StatusCode} sending mail\n{result.ReasonPhrase}");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
|
||||
namespace PodNoms.Api {
|
||||
public class Startup {
|
||||
@@ -218,6 +219,7 @@ namespace PodNoms.Api {
|
||||
services.AddScoped<IUrlProcessService, UrlProcessService>();
|
||||
services.AddScoped<INotifyJobCompleteService, NotifyJobCompleteService>();
|
||||
services.AddScoped<IAudioUploadProcessService, AudioUploadProcessService>();
|
||||
services.AddScoped<IEmailSender, PodNoms.Api.Services.Auth.EmailSender>();
|
||||
services.AddScoped<IMailSender, MailgunSender>();
|
||||
services.AddHttpClient<Services.Gravatar.GravatarHttpClient>();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"App": {
|
||||
"Version": "0.22.0",
|
||||
"SiteUrl": "http://localhost:4200",
|
||||
"RssUrl": "http://localhost:5000/rss/"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
|
||||
Reference in New Issue
Block a user