You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Angular 2+/NodeJS API实现用户认证?含现有MySQL用户API场景

Hey there! Let's break down your two questions step by step—first setting up user authentication on the Node.js API side, then implementing the auth flow in Angular 2+ using your existing user data API.


1. Implementing User Authentication in Node.js API (Angular 2+ Friendly)

The most common and secure approach for RESTful APIs is using JWT (JSON Web Tokens)—it's stateless, easy to integrate with Angular, and works well with MySQL. I'll assume you're using Express as your Node.js framework here.

Step 1: Install Required Dependencies

First, add the packages we'll need for auth, encryption, and database interactions:

npm install jsonwebtoken bcryptjs express mysql2

Step 2: Add a Login Endpoint & Auth Middleware

Your existing API returns full user data—we'll add a login endpoint to validate credentials and issue tokens, plus middleware to protect sensitive routes.

Here's a sample implementation:

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const mysql = require('mysql2/promise');
const router = express.Router();

// Configure your MySQL connection (adjust to your DB credentials)
const db = mysql.createPool({
  host: 'localhost',
  user: 'your_db_user',
  password: 'your_db_password',
  database: 'your_db_name'
});

// Login endpoint: Validate user and return JWT
router.post('/login', async (req, res) => {
  try {
    const { username, password } = req.body;

    // Fetch user from database (never return plaintext passwords!)
    const [users] = await db.execute('SELECT id, username, password FROM users WHERE username = ?', [username]);
    if (users.length === 0) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }
    const user = users[0];

    // Verify password (only works if passwords are hashed in the DB!)
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    // Generate JWT token (store the secret in environment variables for production!)
    const token = jwt.sign(
      { userId: user.id, username: user.username },
      'your_secure_secret_key',
      { expiresIn: '1h' } // Token expires after 1 hour
    );

    // Return token and sanitized user data (no password!)
    res.json({ 
      token, 
      user: { id: user.id, username: user.username } 
    });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

// Middleware to protect routes: Verify JWT before allowing access
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1]; // Extract token from "Bearer <token>"

  if (!token) {
    return res.status(401).json({ message: 'Access token required' });
  }

  jwt.verify(token, 'your_secure_secret_key', (err, user) => {
    if (err) {
      return res.status(403).json({ message: 'Invalid or expired token' });
    }
    req.user = user; // Attach user data to request for downstream routes
    next();
  });
};

// Protect your existing /api/users endpoint (optional but recommended)
router.get('/users', authenticateToken, async (req, res) => {
  try {
    const [users] = await db.execute('SELECT id, username, email FROM users'); // Exclude passwords!
    res.json(users);
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;

⚠️ Critical Note: If your MySQL users store plaintext passwords, you must hash them first! Use bcrypt.hash(password, 10) to encrypt passwords before saving them to the database (update your user registration logic or run a one-time script to hash existing passwords).

Step 3: Secure Other Routes

Use the authenticateToken middleware for any route that requires a logged-in user (e.g., /api/profile, /api/orders).


2. Implementing User Authentication in Angular 2+

We'll build a complete auth flow using the Node.js login API we just created. If you can't modify the backend yet, I'll also include a (very insecure) temporary workaround using your full user API.

Step 1: Create an Auth Service

Generate a service to handle login, logout, and user state:

ng generate service auth

Update the service with auth logic:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';

// Define a user interface to type our data
interface User {
  id: number;
  username: string;
}

interface AuthResponse {
  token: string;
  user: User;
}

@Injectable({ providedIn: 'root' })
export class AuthService {
  private currentUserSubject: BehaviorSubject<User | null>;
  public currentUser: Observable<User | null>;

  constructor(private http: HttpClient) {
    // Load user from localStorage when the app starts
    const savedUser = JSON.parse(localStorage.getItem('currentUser') || 'null');
    this.currentUserSubject = new BehaviorSubject<User | null>(savedUser);
    this.currentUser = this.currentUserSubject.asObservable();
  }

  // Get the current user synchronously
  public get currentUserValue(): User | null {
    return this.currentUserSubject.value;
  }

  login(username: string, password: string): Observable<User> {
    return this.http.post<AuthResponse>('http://localhost:3000/api/login', { username, password })
      .pipe(
        map(response => {
          // Store token and user data in localStorage
          localStorage.setItem('token', response.token);
          localStorage.setItem('currentUser', JSON.stringify(response.user));
          // Update the user state
          this.currentUserSubject.next(response.user);
          return response.user;
        })
      );
  }

  logout(): void {
    // Clear stored data and reset user state
    localStorage.removeItem('token');
    localStorage.removeItem('currentUser');
    this.currentUserSubject.next(null);
  }
}

Step 2: Add an HTTP Interceptor to Attach Tokens

Generate an interceptor to automatically add the JWT to every request:

ng generate interceptor auth

Update the interceptor:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    const token = localStorage.getItem('token');
    if (token) {
      // Clone the request and add the Authorization header
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }
    return next.handle(request);
  }
}

Register the interceptor in app.module.ts:

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ]
})
export class AppModule { }

Step 3: Build a Login Component

Generate a login form component:

ng generate component login

Template (login.component.html):

<div class="login-form">
  <h2>Sign In</h2>
  <form (ngSubmit)="onSubmit()">
    <div class="form-group">
      <label>Username</label>
      <input type="text" [(ngModel)]="username" name="username" required>
    </div>
    <div class="form-group">
      <label>Password</label>
      <input type="password" [(ngModel)]="password" name="password" required>
    </div>
    <button type="submit" class="login-btn">Login</button>
    <div *ngIf="errorMessage" class="error">{{ errorMessage }}</div>
  </form>
</div>

Component Logic (login.component.ts):

import { Component } from '@angular/core';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html'
})
export class LoginComponent {
  username = '';
  password = '';
  errorMessage = '';

  constructor(private authService: AuthService, private router: Router) {}

  onSubmit(): void {
    this.authService.login(this.username, this.password).subscribe({
      next: () => {
        // Redirect to a protected route after login
        this.router.navigate(['/dashboard']);
      },
      error: (err) => {
        this.errorMessage = err.error.message || 'Login failed. Please try again.';
      }
    });
  }
}

Step 4: Add Route Guards to Protect Pages

Generate a guard to block unauthenticated users from accessing protected routes:

ng generate guard auth

Update the guard:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const currentUser = this.authService.currentUserValue;
    if (currentUser) {
      return true; // Allow access if user is logged in
    }
    // Redirect to login page with the original URL to return to after login
    this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
    return false;
  }
}

Use the guard in your routing (app-routing.module.ts):

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { AuthGuard } from './auth.guard';

const routes: Routes = [
  { path: 'login', component: LoginComponent },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

If you can't modify the backend yet, you can validate credentials on the frontend—but this is extremely insecure (all user data, including passwords, will be exposed to clients). Only use this for testing:

Update the login method in AuthService:

login(username: string, password: string): Observable<User> {
  return this.http.get<User[]>('http://localhost:3000/api/users')
    .pipe(
      map(users => {
        // Find matching user (only works if passwords are plaintext!)
        const user = users.find(u => u.username === username && u.password === password);
        if (!user) {
          throw new Error('Invalid credentials');
        }
        // Store user in localStorage (no token available)
        localStorage.setItem('currentUser', JSON.stringify(user));
        this.currentUserSubject.next(user);
        return user;
      })
    );
}

The rest of the auth flow (route guards, login component) works the same, but never use this in production.


内容的提问来源于stack exchange,提问作者Platiplus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:31:02