如何在Angular(v5)中从Node/Express获取JWT存入LocalStorage并跳转至Profile路由
实现步骤:从Node/Express获取JWT并在Angular中处理
我来帮你一步步完成这个需求,分后端(Node/Express)和前端(Angular)两部分梳理:
一、后端(Node/Express)配置
首先要确保你的登录接口能正确生成并返回JWT,这里以routes/auth.js为例:
1. 安装依赖
先确保你装了生成JWT和加密密码的依赖:
npm install jsonwebtoken bcryptjs cors
2. 编写登录接口
在routes/auth.js中添加登录逻辑,验证用户后生成JWT返回:
const express = require('express'); const router = express.Router(); const User = require('../models/schema'); const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); // 假设你在config目录下有config.js,存储JWT密钥 const config = require('../config/config'); // 登录接口 router.post('/login', async (req, res) => { try { const { email, password } = req.body; // 查找用户 const user = await User.findOne({ email }); if (!user) { return res.status(400).json({ msg: '用户不存在' }); } // 验证密码(假设你存储的是加密后的密码) const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { return res.status(400).json({ msg: '密码错误' }); } // 生成JWT const tokenPayload = { id: user._id, name: user.name, email: user.email }; jwt.sign( tokenPayload, config.JWT_SECRET, // 你的JWT密钥,要存在环境变量里更安全 { expiresIn: '7d' }, // 设置token过期时间,比如7天 (err, token) => { if (err) throw err; res.json({ token, user: { id: user._id, name: user.name, email: user.email } }); } ); } catch (err) { console.error(err.message); res.status(500).json({ msg: '服务器内部错误' }); } }); module.exports = router;
3. 挂载路由并配置CORS
在根目录的index.js中挂载路由,并解决跨域问题:
const express = require('express'); const app = express(); const authRoutes = require('./routes/auth'); const cors = require('cors'); // 配置CORS,允许前端跨域请求 app.use(cors()); // 解析JSON请求体 app.use(express.json()); // 挂载认证路由 app.use('/api/auth', authRoutes); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`服务器运行在端口${PORT}`));
二、前端(Angular)配置
接下来处理Angular部分,实现登录请求、存储JWT、跳转Profile路由的逻辑:
1. 创建Auth服务
在services目录下新建auth.service.ts,封装登录、token存储和路由跳转逻辑:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Router } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthService { private apiBaseUrl = 'http://localhost:3000/api/auth'; // 你的后端API地址 constructor(private http: HttpClient, private router: Router) { } // 发送登录请求 login(email: string, password: string): Observable<any> { return this.http.post(`${this.apiBaseUrl}/login`, { email, password }); } // 把JWT存储到LocalStorage saveToken(token: string): void { localStorage.setItem('jwt_token', token); } // 存储当前用户信息到LocalStorage saveUser(user: any): void { localStorage.setItem('current_user', JSON.stringify(user)); } // 获取LocalStorage中的token getToken(): string | null { return localStorage.getItem('jwt_token'); } // 登出逻辑 logout(): void { localStorage.removeItem('jwt_token'); localStorage.removeItem('current_user'); this.router.navigate(['/login']); } }
2. 改造Login组件
在login.component.ts中处理表单提交,调用Auth服务完成登录:
import { Component } from '@angular/core'; import { AuthService } from '../../services/auth.service'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent { email: string = ''; password: string = ''; errorMessage: string = ''; constructor(private authService: AuthService) { } onLoginSubmit(): void { this.authService.login(this.email, this.password).subscribe({ next: (response) => { // 存储token和用户信息 this.authService.saveToken(response.token); this.authService.saveUser(response.user); // 跳转至Profile路由 this.authService.router.navigate(['/profile']); }, error: (err) => { this.errorMessage = err.error.msg || '登录失败,请检查账号密码'; console.error(err); } }); } }
对应的login.component.html示例:
<div class="login-form"> <h2>用户登录</h2> <form (ngSubmit)="onLoginSubmit()"> <div class="form-group"> <label>邮箱</label> <input type="email" [(ngModel)]="email" name="email" required> </div> <div class="form-group"> <label>密码</label> <input type="password" [(ngModel)]="password" name="password" required> </div> <button type="submit" class="login-btn">登录</button> <p *ngIf="errorMessage" class="error-text">{{ errorMessage }}</p> </form> </div>
3. 配置Profile路由与守卫
为了确保只有登录用户能访问Profile页面,添加路由守卫:
(1)创建AuthGuard
在services目录下新建auth.guard.ts:
import { Injectable } from '@angular/core'; import { CanActivate, 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(): boolean { if (this.authService.getToken()) { return true; // 有token,允许访问 } else { this.router.navigate(['/login']); // 无token,跳转登录页 return false; } } }
(2)配置路由
在app.module.ts中更新路由配置:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { LoginComponent } from './components/login/login.component'; import { ProfileComponent } from './components/profile/profile.component'; import { HomeComponent } from './components/home/home.component'; import { AuthGuard } from './services/auth.guard'; const appRoutes: Routes = [ { path: '', component: HomeComponent }, { path: 'login', component: LoginComponent }, // 用AuthGuard保护Profile路由 { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] }, { path: '**', redirectTo: '' } ]; @NgModule({ declarations: [ AppComponent, LoginComponent, ProfileComponent, HomeComponent // 其他组件 ], imports: [ BrowserModule, HttpClientModule, FormsModule, RouterModule.forRoot(appRoutes) ], providers: [AuthGuard], bootstrap: [AppComponent] }) export class AppModule { }
4. 改造Profile组件
在profile.component.ts中获取用户信息并展示:
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../../services/auth.service'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', styleUrls: ['./profile.component.css'] }) export class ProfileComponent implements OnInit { currentUser: any; constructor(public authService: AuthService) { } ngOnInit(): void { // 从LocalStorage获取用户信息 const userStr = localStorage.getItem('current_user'); this.currentUser = userStr ? JSON.parse(userStr) : null; } }
对应的profile.component.html示例:
<div class="profile-card"> <h2>个人资料</h2> <div class="info-item"> <span>姓名:</span>{{ currentUser.name }} </div> <div class="info-item"> <span>邮箱:</span>{{ currentUser.email }} </div> <div class="info-item"> <span>用户ID:</span>{{ currentUser.id }} </div> <button (click)="authService.logout()" class="logout-btn">登出</button> </div>
内容的提问来源于stack exchange,提问作者Manish Vashisth
相关产品推荐
相关产品推荐

