【发布时间】:2020-05-21 04:27:10
【问题描述】:
我遇到了一个问题(我正在学习 C# 和 Angular),当我尝试将数据传输到我的 API 时,它会出现我无法解决的错误。
当用户请求忘记密码的电子邮件时,他们会收到一个链接,其中包含他们的电子邮件和 Microsoft Identity 生成的令牌。当点击该链接时,他们会被带到一个页面,允许他们输入新密码并进行确认,然后该数据将发送回 API 以更改密码。
我遇到的问题是由于缺乏经验,我不确定如何解决。抛出的错误是:
zone.js:3372 POST http://localhost:5000/api/auth/ResetPasswordundefinedemail@domain.com 404(未找到)
如果我使用 Postman 将详细信息作为 JSON 数据输入到帖子正文中发送,它可以正常工作并且密码已成功更改。但是当通过 Angular 应用程序提交时,它出错了,我很确定这是由于 Angular 应用程序发送到 API 的数据的格式。
在用户输入新密码的 Angular 模块中,它会将用户的电子邮件和令牌以及密码数据提交给 API。我需要弄清楚的是如何将电子邮件和令牌放入包含新密码的模型对象中。文件如下:
更改密码.component.ts
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../../_services/auth.service';
import { AlertifyService } from '../../_services/alertify.service';
@Component({
selector: 'app-email-change-password',
templateUrl: './email-change-password.component.html',
styleUrls: ['./email-change-password.component.css']
})
export class EmailChangePasswordComponent {
model: any;
email: string;
token: string;
constructor(private activatedRoute: ActivatedRoute, private authService: AuthService, private alertify: AlertifyService, private router: Router) {
this.activatedRoute.queryParams.subscribe(params => {
this.email = params['email'];
this.token = params['token'];
// console.log(this.email);
// console.log(this.token);
});
}
resetChangePassword() {
this.authService.resetChangePassword(this.email, this.token, this.model).subscribe(next => {
}, error => {
this.alertify.error(error);
}, () => {
this.router.navigate(['/passwordchanged']);
});
}
}
从此文件中,模型包含用户提交的密码和确认的密码。它还从您的 URL 参数中获取电子邮件和令牌。然后通过身份验证服务将其发送到 API。
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { JwtHelperService } from '@auth0/angular-jwt';
import { environment } from '../../environments/environment';
import { Clients } from '../_models/clients';
@Injectable({
providedIn: 'root'
})
export class AuthService {
// Add a variable for out login url
baseUrl = environment.apiUrl + 'auth/';
jwtHelper = new JwtHelperService();
decodedToken: any;
// inject the HttpClient module and service into the constructor
constructor(private http: HttpClient) { }
// Add a new login method that will take the model object of type any form the login component and pass the
// credentials to the API to be authenticated
login(model: any) {
return this.http.post(this.baseUrl + 'login', model)
// A token is returned in the response from the server. Use RXJS operators by passing them through a pipe.
// Transform the response with the map operator and store it locally (this is the token being stored in local storage)
.pipe(
map((response: any) => {
const user = response;
if (user) {
localStorage.setItem('token', user.token);
this.decodedToken = this.jwtHelper.decodeToken(user.token);
}
})
);
}
// Register a new client user
register(client: Clients) {
return this.http.post(this.baseUrl + 'register', client);
}
// check if a user is logged into the portal or not.
loggedIn() {
const token = localStorage.getItem('token');
return !this.jwtHelper.isTokenExpired(token);
}
// Send forgot password email
resetpassword(model: any) {
return this.http.post(this.baseUrl + 'forgotpassword', model);
}
// Change a users forgotten password
resetChangePassword(email: string, token: string, model: any) {
return this.http.post(this.baseUrl + 'ResetPassword' + model + email, token);
}
}
AuthController.cs(我已经删除了不相关的内容)
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Outmatch.API.Data;
using Outmatch.API.Dtos;
using Outmatch.API.Models;
namespace Outmatch.API.Controllers
{
// Route will be api/auth (http://localhost:5000/api/auth)
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
// Inject the auth repository and the programs configuration into the controller.
private readonly IConfiguration _config;
private readonly IMapper _mapper;
private readonly SignInManager<User> _signInManager;
private readonly UserManager<User> _userManager;
private readonly IClientRepository _repo;
private readonly IMailRepository _MailRepository;
private readonly IConfiguration _configuration;
private readonly IResetPasswordRepository _resetPasswordRepository;
public AuthController(IConfiguration config, IMapper mapper, UserManager<User> userManager, SignInManager<User> signInManager,
IClientRepository repo, IMailRepository MailRepository, IConfiguration configuration, IResetPasswordRepository resetPasswordRepository)
{
_resetPasswordRepository = resetPasswordRepository;
_configuration = configuration;
_MailRepository = MailRepository;
_repo = repo;
_userManager = userManager;
_signInManager = signInManager;
_mapper = mapper;
_config = config;
}
[HttpPost("ResetPassword")]
public async Task<IActionResult> ResetPassword(PasswordResetDto passwordResetDto)
{
if (ModelState.IsValid)
{
var result = await _resetPasswordRepository.ResetPasswordAsync(passwordResetDto);
if (result != null)
return Ok(result);
return BadRequest(result);
}
return BadRequest("Invalid details");
}
}
}
IResetPasswordRepository:
using System.Threading.Tasks;
using Outmatch.API.Dtos;
using Outmatch.API.Models;
namespace Outmatch.API.Data
{
public interface IResetPasswordRepository
{
Task<User> ResetPasswordAsync(PasswordResetDto passwordResetDto);
}
}
重置密码存储库:
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.WebUtilities;
using Outmatch.API.Dtos;
using Outmatch.API.Models;
namespace Outmatch.API.Data
{
public class ResetPasswordRepository : IResetPasswordRepository
{
private readonly UserManager<User> _userManager;
public ResetPasswordRepository(UserManager<User> userManager)
{
_userManager = userManager;
}
public async Task<User> ResetPasswordAsync(PasswordResetDto passwordResetDto)
{
var user = await _userManager.FindByEmailAsync(passwordResetDto.Email);
if (user == null)
return null;
var decodedToken = WebEncoders.Base64UrlDecode(passwordResetDto.Token);
string normalToken = Encoding.UTF8.GetString(decodedToken);
if (passwordResetDto.NewPassword != passwordResetDto.ConfirmPassword)
return null;
var result = await _userManager.ResetPasswordAsync(user, normalToken, passwordResetDto.NewPassword);
if (result.Succeeded)
return null;
return null;
}
}
}
PasswordResetDto:
using System.ComponentModel.DataAnnotations;
namespace Outmatch.API.Dtos
{
public class PasswordResetDto
{
[Required]
public string Token { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(20, MinimumLength = 5)]
public string NewPassword { get; set; }
[Required]
[StringLength(20, MinimumLength = 5)]
public string ConfirmPassword { get; set; }
}
}
我知道这是由于 API URL 不正确,但我不确定如何正确格式化,以便将用户电子邮件、令牌、密码和确认密码正确发送到 API。
对此的任何帮助将不胜感激!
【问题讨论】:
-
邮递员使用的url是什么
-
localhost:5000/api/auth/resetpassword 是使用的,工作正常。
-
this.http.post(this.baseUrl + 'ResetPassword' + model + email, token);在这里您尝试字符串 concat 这将导致 localhost/restpassword/modelemailtoken -
已更正以反映:
this.http.post(this.baseUrl + 'ResetPassword', model, token, email);现在收到“预期 2-3 个参数,但得到 4 个”的错误。这很奇怪,因为它根据需要传递了相同的 4 个参数 -
Post 只有两个重载主体,httpoptions