当前位置: 首页 > news >正文

Spring Boot + Angular 实现安全登录注册系统:全栈开发指南

引言:现代Web应用认证的重要性

在当今数字化时代,用户认证是Web应用的基石。无论是电商平台、社交媒体还是企业系统,安全的登录注册功能都至关重要。本文将手把手教你使用Spring Boot作为后端、Angular作为前端,构建一个完整的登录注册系统。

系统整体架构设计

我们的系统采用经典的前后端分离架构:

graph TDsubgraph Frontend[Angular前端]A[登录组件] -->|调用| B[认证服务]C[注册组件] -->|调用| BD[路由守卫] -->|保护| E[受保护路由]F[HTTP拦截器] -->|添加Token| G[HTTP请求]endsubgraph Backend[Spring Boot后端]H[认证控制器] -->|处理| I[注册端点]H -->|处理| J[登录端点]K[安全配置] -->|保护| L[受保护API]M[JWT工具] -->|生成/验证| N[认证]O[用户仓库] -->|数据操作| P[数据库]endFrontend -->|HTTP API调用| Backend

架构核心组件:

  1. 前端:Angular应用,包含登录/注册组件、认证服务和路由守卫
  2. 后端:Spring Boot应用,提供REST API,处理认证和用户管理
  3. 通信:HTTPS协议,JSON数据格式
  4. 认证:基于JWT(JSON Web Token)的无状态认证机制

后端实现:Spring Boot安全认证

技术栈

  • Spring Security
  • Spring Data JPA
  • JJWT库
  • H2数据库(开发环境)
  • Lombok

关键代码实现

1. 用户实体类
@Entity
@Data
@NoArgsConstructor
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(unique = true)private String email;private String password;private String name;private String role = "USER";private LocalDateTime createdAt = LocalDateTime.now();
}
2. JWT工具类
@Component
public class JwtUtil {private final String SECRET_KEY = "your-strong-secret-key-here";private final long EXPIRATION_MS = 10 * 60 * 60 * 1000; // 10小时public String generateToken(UserDetails userDetails) {return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_MS)).signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();}public Boolean validateToken(String token, UserDetails userDetails) {final String username = extractUsername(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}
}
3. 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsServiceImpl userDetailsService;@Autowiredprivate JwtUtil jwtUtil;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/api/auth/**", "/h2-console/**").permitAll().anyRequest().authenticated().and().addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtUtil)).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);// 允许H2控制台的帧访问http.headers().frameOptions().disable();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
4. 认证控制器
@RestController
@RequestMapping("/api/auth")
public class AuthController {@PostMapping("/register")public ResponseEntity<?> register(@Valid @RequestBody RegisterRequest request) {if (userRepository.existsByEmail(request.getEmail())) {return ResponseEntity.badRequest().body(Map.of("message", "Email already exists"));}User user = new User();user.setEmail(request.getEmail());user.setName(request.getName());user.setPassword(passwordEncoder.encode(request.getPassword()));userRepository.save(user);return ResponseEntity.ok(Map.of("message", "User registered successfully"));}@PostMapping("/login")public ResponseEntity<?> login(@Valid @RequestBody LoginRequest request) {try {Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getEmail(),request.getPassword()));UserDetails userDetails = (UserDetails) authentication.getPrincipal();String jwt = jwtUtil.generateToken(userDetails);return ResponseEntity.ok(new AuthResponse(jwt));} catch (BadCredentialsException e) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("message", "Invalid credentials"));}}
}

前端实现:Angular认证系统

项目结构

src/
├── app/
│   ├── core/
│   │   ├── guards/          # 路由守卫
│   │   ├── interceptors/     # HTTP拦截器
│   │   └── services/         # 核心服务
│   ├── modules/
│   │   ├── auth/             # 认证模块
│   │   └── dashboard/        # 主应用模块
│   ├── shared/               # 共享模块
│   ├── app-routing.module.ts # 路由配置
│   └── app.module.ts         # 主模块

关键组件实现

1. 认证服务
@Injectable({ providedIn: 'root' })
export class AuthService {private readonly apiUrl = `${environment.apiUrl}/auth`;private currentUserSubject = new BehaviorSubject<User | null>(null);public currentUser$ = this.currentUserSubject.asObservable();constructor(private http: HttpClient,private tokenService: TokenService,private router: Router) {const user = localStorage.getItem('currentUser');if (user) {this.currentUserSubject.next(JSON.parse(user));}}login(credentials: { email: string; password: string }): Observable<any> {return this.http.post<{ token: string }>(`${this.apiUrl}/login`, credentials).pipe(tap(response => {this.tokenService.setToken(response.token);this.fetchCurrentUser();}));}fetchCurrentUser(): void {this.http.get<User>(`${environment.apiUrl}/users/me`).subscribe({next: user => {this.currentUserSubject.next(user);localStorage.setItem('currentUser', JSON.stringify(user));},error: () => this.logout()});}logout(): void {this.tokenService.removeToken();this.currentUserSubject.next(null);localStorage.removeItem('currentUser');this.router.navigate(['/login']);}
}
2. 登录组件
@Component({selector: 'app-login',templateUrl: './login.component.html',styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {loginForm: FormGroup;isLoading = false;errorMessage: string | null = null;returnUrl: string | null = null;showPassword = false;constructor(private fb: FormBuilder,private authService: AuthService,private router: Router,private route: ActivatedRoute) {this.loginForm = this.fb.group({email: ['', [Validators.required, Validators.email]],password: ['', Validators.required],rememberMe: [false]});}onSubmit(): void {if (this.loginForm.invalid) return;this.isLoading = true;this.errorMessage = null;const { email, password } = this.loginForm.value;this.authService.login({ email, password }).subscribe({next: () => {this.router.navigateByUrl(this.returnUrl || '/dashboard');},error: (err) => {this.errorMessage = '登录失败,请检查您的凭据';this.isLoading = false;}});}
}
3. 登录组件模板
<div class="login-container"><mat-card class="login-card"><mat-card-header><mat-card-title>欢迎回来</mat-card-title><mat-card-subtitle>请登录您的账户</mat-card-subtitle></mat-card-header><mat-card-content><form [formGroup]="loginForm" (ngSubmit)="onSubmit()"><mat-form-field appearance="outline"><mat-label>电子邮箱</mat-label><input matInput formControlName="email" type="email"><mat-icon matSuffix>mail</mat-icon><mat-error *ngIf="loginForm.get('email')?.hasError('required')">邮箱为必填项</mat-error></mat-form-field><mat-form-field appearance="outline"><mat-label>密码</mat-label><input matInput [type]="showPassword ? 'text' : 'password'" formControlName="password"><button type="button" mat-icon-button matSuffix(click)="togglePasswordVisibility()"><mat-icon>{{ showPassword ? 'visibility_off' : 'visibility' }}</mat-icon></button></mat-form-field><button mat-raised-button color="primary" type="submit"[disabled]="loginForm.invalid || isLoading"><span *ngIf="!isLoading">登录</span><mat-spinner *ngIf="isLoading" diameter="20"></mat-spinner></button></form></mat-card-content></mat-card>
</div>
4. HTTP拦截器
@Injectable()
export class AuthInterceptor implements HttpInterceptor {constructor(private tokenService: TokenService,private authService: AuthService,private router: Router) {}intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {const token = this.tokenService.getToken();let authReq = request;if (token) {authReq = request.clone({setHeaders: {Authorization: `Bearer ${token}`}});}return next.handle(authReq).pipe(catchError((error: HttpErrorResponse) => {if (error.status === 401) {this.authService.logout();this.router.navigate(['/login'], { queryParams: { expired: true } });}return throwError(() => error);}));}
}

系统数据流分析

登录流程

UserAngularSpringBootDatabase输入凭据并提交POST /api/auth/login查询用户返回用户数据生成JWT200 OK (含JWT)存储Token跳转到主页401 Unauthorized显示错误alt[认证成功][认证失败]UserAngularSpringBootDatabase

注册流程

UserAngularSpringBootDatabase填写注册表单POST /api/auth/register检查邮箱唯一性密码加密保存用户保存成功200 OK显示成功消息400 Bad Request显示错误alt[邮箱可用][邮箱已存在]UserAngularSpringBootDatabase

安全架构设计

HTTPS
Angular前端
Spring Boot后端
Spring Security
JWT认证
Token生成
Token验证
密码加密
BCrypt
CORS配置
CSRF防护

安全措施:

  1. 密码安全:BCrypt强哈希算法存储密码
  2. 传输安全:强制使用HTTPS
  3. 令牌安全
    • JWT设置合理有效期(建议2小时)
    • 使用强密钥(256位以上)
  4. 跨域控制:严格的白名单策略
  5. 输入验证:前后端双重验证

部署架构

HTTPS
静态文件
API代理
用户
Nginx
Angular应用
Spring Boot应用
MySQL数据库集群

部署要点:

  1. 使用Nginx作为反向代理和静态文件服务器
  2. Spring Boot应用使用内嵌Tomcat
  3. 数据库主从复制提高可用性
  4. 使用环境变量管理敏感信息
  5. 配置监控和日志系统

总结与扩展

我们实现了一个完整的登录注册系统,具有以下特点:

✅ 前后端分离架构
✅ JWT无状态认证
✅ 响应式表单验证
✅ 路由级权限控制
✅ 多层安全防护

扩展方向:

  1. 添加社交登录(OAuth2)
  2. 实现双因素认证
  3. 集成短信/邮箱验证
  4. 添加RBAC权限管理系统
  5. 实现密码重置功能

项目源码
GitHub - Spring Boot后端
GitHub - Angular前端

通过本文,你应该已经掌握了使用Spring Boot和Angular构建登录注册系统的核心知识和技能。这个架构不仅适用于登录注册功能,还可以作为任何需要用户认证的Web应用的基础。

http://www.lryc.cn/news/613927.html

相关文章:

  • 【AI】从零开始的文本分类模型实战:从数据到部署的全流程指南
  • BBH详解:面向大模型的高阶推理评估基准与数据集分析
  • C++信息学奥赛一本通-第一部分-基础一-第3章-第1节
  • 支持向量机(SVM)全解析:原理、类别与实践
  • MySQL数据库操作练习
  • Go通道操作全解析:从基础到高并发模式
  • 微算法科技(NASDAQ:MLGO)使用循环QSC和QKD的量子区块链架构,提高交易安全性和透明度
  • 机器学习——KMeans聚类算法(算法原理+超参数详解+实战案例)
  • 计算机视觉CS231n学习(5)
  • 手搓MCP全流程指南:从本地开发部署到PyPI公开发布
  • 构建健壮的数据库连接池:高并发 Web 应用的制胜之匙
  • 面向真实场景的定制化图像降质模型设计方案
  • 深度剖析主流AI大模型的编程语言与架构选择:行业实践与技术细节解读
  • Linux系统编程Day9 -- gdb (linux)和lldb(macOS)调试工具
  • 什么是2米分辨率卫星影像数据?
  • Baumer相机如何通过YoloV8深度学习模型实现高速公路车辆的实时检测计数(C#代码UI界面版)
  • 无服务器日志分析由 Elasticsearch 提供支持,推出新的低价层
  • 14. isaacsim4.2教程-April Tags/给相机加噪声
  • 解析工业机器视觉中的飞拍技术
  • MySQL binlog日志文件转为可正常查看的文本文件
  • 双目标定中旋转矩阵参数应用及旋转角度计算(聚焦坐标系平行)
  • 系统网络端口安全扫描脚本及详解
  • Fabarta个人专属智能体:三维搜索链+动态大纲重构教材开发范式
  • 南方略咨询与与清源科技正式启动国际市场GTM流程规划咨询项目!!!
  • 论文阅读:User Behavior Simulation with Large Language Model-based Agents
  • Langchain入门:构建一个基于SQL数据的问答系统
  • 云平台运维工具 ——Azure 原生工具
  • 化工厂安全升级:分布式光纤传感的 “实时监测 + 精准预警” 方案
  • 高校合作 | 世冠科技联合普华、北邮项目入选教育部第二批工程案例
  • 分布式膛压应变测量系统