После недопустимого входа на сервер ASP.NET MVC, как я могу записать текст ошибки в возвращенном ответе Json и отобразить его в клиенте Angular?

Страница входа в клиент Angular 9

Я хочу отображать конкретное возвращаемое сообщение об ошибке в элементе <h4> вместо общего сообщения, которое отображается в данный момент. Примечание. Я обновил страницу, указав решение, которое собираюсь использовать.

<div class = "navbar bg-info mb-1">
   <a class = "navbar-brand text-white">The ACTS Factory Authentication</a>
</div>
<!-- I want to put the specific error condition here -->
<h4 *ngIf = "showError" class = "p-2 bg-danger text-white">
<!-- Invalid username or password! --> {{theError}}      
</h4>
<form novalidate #authForm = "ngForm" class = "m-3" title = "LoginForm">
   <div class = "form-group">
     <label>Name:</label>
     <input #name = "ngModel" name = "name" class = "form-control"
            [(ngModel)] = "authService.name" required />

     <div *ngIf = "name.invalid" class = "text-danger">
       Please enter your user name
     </div>

   </div>
   <div class = "form-group">
     <label>Password:</label>
     <input type = "password" #password = "ngModel" name = "password"
            class = "form-control" [(ngModel)] = "authService.password" required />
     <div *ngIf = "password.invalid" class = "text-danger">
       Please enter your password
     </div>
   </div>
   <div class = "text-center pt-2">
     <button type = "button" class = "btn btn-primary font-weight-bold" [disabled] = "authForm.invalid"
             (click) = "login()">
       Please Login
     </button>
   </div>
 </form>

Угловой 9-компонентный

Я вхожу в систему из этого клиентского компонента Angular. Когда код состояния ответа равен 400 Bad Request, result имеет значение false, и в элементе <h4> отображается общее сообщение об ошибке. Здесь метод login() подписывается на метод Login() в репозитории службы аутентификации. Возвращенный объект ответа или свойство, содержащее текст ошибки, должен вернуться сюда, чтобы быть добавленным в HTML-отображение. Примечание. Я обновил код решением, которое собираюсь использовать.

 import { Component } from "@angular/core";
 import { AuthenticationService } from "./authentication.service";
 import { HttpErrorResponse } from "@angular/common/http";

 @Component({
    templateUrl: "authentication.component.html"
 })
 export class AuthenticationComponent {

   showError: boolean = false;
   theError?: string = null;

   constructor(public authService: AuthenticationService) { }

   login() {
    // this.showError = false;
    // this.authService.login().subscribe(result => { this.showError = !result });

    // new Solution:
        this.authService.login().subscribe(result => { /* success action */ this.showError = !result },  // if true result, "showError" = false
         (err: HttpErrorResponse) => { /* error action */ console.error(err) },
         () => { /* complete (after success OR error) action */
         if (this.authService.theError != null) {
         this.theError = this.authService.theError;
         this.showError = true;
       }})

   }
 }
 

Метод входа Angular 9 в репозиторий службы аутентификации клиента

Этот метод входа вызывает наблюдаемый метод источника данных login(), определяет, был ли получен действительный (истинный или ложный) ответ, и сопоставляет возвращаемые свойства, содержащиеся в ответе, с локальными переменными. Примечание. Я обновил код решением, которое собираюсь использовать.

   // new variable for solution
   theError: string = null;

   login(): Observable<boolean> {
     this.authenticated = false;

     return this.dataSource.login(this.userName, this.userPwd).pipe(
       map(response => {
         if (response) {
           this.callbackUrl = null;
           this.authenticated = true;
           this.password = null
           this.router.navigateByUrl(this.callbackUrl || "appmenu");
         }
         // new code for solution - to capture error from datasource response object
         else {
                this.theError = this.dataSource.loginError;
         }

         this.profileEmail = null;
         this.profilePhone = null;

         if (this.dataSource.teamUser) {
           this.isTeamUser = this.dataSource.teamUser;
         }
         else {
         this.isTeamUser = false;
       }

       return this.authenticated = true;
     }),
     catchError(e => {
       this.authenticated = false;

    [I have tried to capture the error text here]   

       return of(false);
      }));
  }

Метод входа в источник данных проверки подлинности клиента Angular 9

Это источник данных для клиента; он отправляет HTTP-запрос на сервер и получает HTTP-ответ. Он также сопоставляет свойства ответа с локальными переменными, определяет целевой URL-адрес и отслеживает необходимые заголовки. Примечание. Я обновил код решением, которое собираюсь использовать.

   // new property in solution to contain login errors
   _loginError?: string = "Server not ready - try again.";
   public get loginError(): string {
   return this._loginError;
   }
   public set loginError(newValue: string) {
     this._loginError = newValue;
   }
   // end new property

   auth_Header: HttpHeaders = new HttpHeaders();
   auth_token: string = null;

   login(theName: string, thePassword: string): Observable<boolean> {
     return this.http.post<any>("/api/account/login",
     { name: theName, password: thePassword })
      .pipe(map(response => {

       // new solution code for capturing error and exiting if
       // the login status code is 203, codes in 400 series do
       // not logically track here.
       this.loginError = response.LoginError;
       if (!response.success) {
         return false;
       }
       // end new code

       this.auth_token = response.success ? response.token : null;    // JWT token generated in server-side AccountController
       this.auth_Header = this.auth_Header.set("Authorization", "Bearer<" + this.auth_token + ">");
       this.authCookie.JWTauthcookie = this.auth_token;  // save for the other datasources

       this.loginTime = response.loginTime;

   // to return user's registered email and phonenumber to client
       this.profileEmail = "";
       this.profileEmail = response.profileEmail;
       this.profilePhone = "";
       this.profilePhone = response.profilePhone;

       }

       this.isAuthenticated = true;
       return response.success;
     }));

Контроллер учетных записей ASP.NET Core MVC

Это контроллер ASP.NET Core MVC, который обрабатывает запрос на вход в систему, ищет в ASP.NET Core Identity имя пользователя и пароль (не показаны в коде) и возвращает код состояния 200 плюс объект JSON при успешном входе в систему. Теперь я возвращаю два конкретных состояния ошибки входа в систему (пользователь не найден или недействительный пароль), которые я хочу отобразить на клиенте после недействительной попытки входа в систему. Я попытался вернуть ошибки с OK вместо BadRequest() кода состояния 400. Но это бесполезно для клиента. Примечание. Я обновил код решением, которое собираюсь использовать.

Любые идеи будут оценены по достоинству. Спасибо.

[HttpPost("/api/account/login")]  
public async Task<IActionResult> Login([FromBody] LoginViewModel creds)
{
    LoginError = "";
    bool loginResult = false;

    object myReturnObject = new object();

    if (ModelState.IsValid) 
    {
        // go look for existing Identity user and try to sign in
        loginResult = await DoLogin(creds);  

        if (loginResult)
        {
            myReturnObject = "{ " + '\n' + "   " + '"' + "success" + '"' + ":" + '"' + signInResult.Succeeded.ToString() + '"' + "," + '\n' +
                    "   " + '"' + "token" + '"' + ':' + '"' + bearerJWTokenString + '"' + "," + '\n' +
                    "   " + '"' + "loginTime" + '"' + ':' + '"' + DateTime.Now.ToShortTimeString() + '"' + "," + '\n' +
                    "   " + '"' + "profileEmail" + '"' + ':' + '"' + profileEmail + '"' + "," + '\n' +
                    "   " + '"' + "profilePhone" + '"' + ':' + '"' + profilePhone + '"' + "," + '\n' +
                    "   " + '"' + "team" + '"' + ':' + '"' + loggedInUserType.ToString() + '"' + "," + '\n' +
                    "}";

            // good login returns this object as a Json file in 
            // the HTTP Response  body
            return Ok(myReturnObject);   
        }
        else
        {   
            // Solution: fixed Json object, and now if bad username or pwd.
            // This returns http status code 203 plus the LoginError json object.
            // It was returning "BadRequest(Json-formatted string)" 
            myReturnObject = "{" + '\n' + "   " + '"' + "InvalidLogin" + '"' + ':' + '"' + "True" + '"' + "," +
                               '\n' + "   " + '"' + "LoginError" + '"' + ':' + '"' + LoginError + '"' +
                               '\n' + "}";
            return StatusCode(203, myReturnObject);
        }

    }

    // bad model state returns - http error 400 Bad Request
    return BadRequest(ModelState.ValidationState.ToString());
}

Снимок экрана с исходной ошибкой, отображаемой в клиенте:


Теперь решение предоставляет конкретную ошибку, когда код состояния 203 возвращается с объектом Json:

Не создавайте JSON вручную на стороне API, это похоже на то, что ваш API возвращает ответ в виде строки вместо JSON (хотя результат выглядит как JSON). Кроме того, вы можете видеть, что результат вашего ответа неверен: в JSON отсутствует запятая. Верните ответ как объект.

Yong Shun 25.07.2024 03:09

@YongShun Спасибо, что заметили недостающую запятую между свойствами. Я думаю ты прав. Мне следовало создать объект и установить его в свою строку, а затем вернуть объект в качестве параметра вместо строки в формате Json. Как я сделал в ответе с хорошим результатом с «MyReturnObject».

Cwinds 25.07.2024 21:53
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
.subscribe(
  data => {/* success action*/},
  (error: HttpErrorResponse) => {/* error action */ console.error(error)},
  () => {/* complite (after success OR error) action */}
)

Мне не удалось вернуть состояние ошибки с кодом состояния 400 в средний раздел «Ошибка» подписки, но с помощью кода возврата 203 я смог вернуть состояние ошибки и зафиксировать его, чтобы сделать состояние ошибки более конкретным. для пользователя. Мое приложение является частным, а не общедоступным, поэтому я бы не рекомендовал так подробно относиться к ошибкам на коммерческом общедоступном сайте. Спасибо.

Cwinds 27.07.2024 01:43

Я предполагаю, что для фиксации состояния ошибки 400 Bad Request в компоненте Angular 9 его метод должен быть подписан на метод http источника данных, а не на метод репозитория службы, который отображает свойства ответа из метода http источника данных. Хм?

Cwinds 27.07.2024 01:58

Кроме того, моя служба аутентификации и источник данных относятся к типам Observable<boolean>. Таким образом, они возвращают компоненту только истинное или ложное значение. Я думаю, мне придется перепроектировать эти методы, чтобы они были Observable<string> или каким-либо типом сущности, чтобы возвращать текст ошибки.

Cwinds 27.07.2024 19:13

Другие вопросы по теме