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

使用Spring Boot + Angular构建安全的登录注册系统

现代全栈开发的完美实践

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
图:系统架构示意图

在当今的Web应用开发中,用户认证是核心功能之一。本文将手把手教你使用Spring Boot作为后端、Angular作为前端,构建一个完整的登录注册系统。


技术栈概览
后端 (Spring Boot)前端 (Angular)
Spring SecurityAngular Router
Spring Data JPAReactive Forms
JWT 认证HTTP Client
H2 数据库 (开发环境)Auth Guard
LombokInterceptor

第一部分:Spring Boot后端实现

1. 项目初始化

使用 Spring Initializr 创建项目,选择:

  • Spring Web
  • Spring Security
  • Spring Data JPA
  • H2 Database
  • Lombok
2. 用户实体类
@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 role = "USER";
}
3. JWT工具类
@Component
public class JwtUtil {private final String SECRET_KEY = "your-secret-key";public String generateToken(UserDetails userDetails) {return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10小时.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));}
}
4. 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsServiceImpl userDetailsService;@Autowiredprivate JwtUtil jwtUtil;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/api/auth/**").permitAll().anyRequest().authenticated().and().addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtUtil)).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
5. 认证控制器
@RestController
@RequestMapping("/api/auth")
public class AuthController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserRepository userRepository;@Autowiredprivate JwtUtil jwtUtil;@PostMapping("/register")public ResponseEntity<?> register(@RequestBody RegisterRequest request) {if (userRepository.existsByEmail(request.getEmail())) {return ResponseEntity.badRequest().body("Email already exists");}User user = new User();user.setEmail(request.getEmail());user.setPassword(new BCryptPasswordEncoder().encode(request.getPassword()));userRepository.save(user);return ResponseEntity.ok("User registered successfully");}@PostMapping("/login")public ResponseEntity<?> login(@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(401).body("Invalid credentials");}}
}

第二部分:Angular前端实现

1. 项目初始化
ng new auth-frontend
ng add @angular/material
ng g s services/auth
ng g guard guards/auth
2. 认证服务
@Injectable({ providedIn: 'root' })
export class AuthService {private apiUrl = 'http://localhost:8080/api/auth';private currentUserSubject = new BehaviorSubject<any>(null);constructor(private http: HttpClient) {const token = localStorage.getItem('token');if (token) {this.currentUserSubject.next(this.decodeToken(token));}}register(credentials: { email: string; password: string }) {return this.http.post(`${this.apiUrl}/register`, credentials);}login(credentials: { email: string; password: string }) {return this.http.post<{ token: string }>(`${this.apiUrl}/login`, credentials).pipe(tap(res => {localStorage.setItem('token', res.token);this.currentUserSubject.next(this.decodeToken(res.token));}));}logout() {localStorage.removeItem('token');this.currentUserSubject.next(null);}private decodeToken(token: string): any {try {return JSON.parse(atob(token.split('.')[1]));} catch (e) {return null;}}
}
3. HTTP拦截器
@Injectable()
export class AuthInterceptor implements HttpInterceptor {intercept(req: HttpRequest<any>, next: HttpHandler) {const token = localStorage.getItem('token');if (token) {const cloned = req.clone({headers: req.headers.set('Authorization', `Bearer ${token}`)});return next.handle(cloned);}return next.handle(req);}
}
4. 路由守卫
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {constructor(private authService: AuthService, private router: Router) {}canActivate(): boolean {if (this.authService.isAuthenticated()) {return true;}this.router.navigate(['/login']);return false;}
}
5. 登录组件模板
<mat-card><mat-card-header><mat-card-title>Login</mat-card-title></mat-card-header><mat-card-content><form [formGroup]="loginForm" (ngSubmit)="onSubmit()"><mat-form-field><input matInput placeholder="Email" formControlName="email"><mat-error>Valid email required</mat-error></mat-form-field><mat-form-field><input matInput type="password" placeholder="Password" formControlName="password"></mat-form-field><button mat-raised-button color="primary" type="submit">Login</button></form></mat-card-content>
</mat-card>

关键功能亮点

  1. JWT无状态认证
    使用JSON Web Token实现无状态会话管理

  2. 密码安全存储
    BCrypt算法加密存储密码

  3. 路由守卫
    防止未授权用户访问受保护路由

  4. 响应式表单
    实时表单验证和错误处理

  5. HTTP拦截器
    自动附加JWT到请求头


部署注意事项

  1. 生产环境切换MySQL数据库:
spring.datasource.url=jdbc:mysql://localhost:3306/auth_db
spring.datasource.username=root
spring.datasource.password=yourpassword
  1. 配置CORS策略:
@Bean
public WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://your-angular-app.com").allowedMethods("*");}};
}
  1. 环境变量管理敏感信息

完整项目结构

backend/
├─ src/
│  ├─ main/
│  │  ├─ java/
│  │  │  ├─ controller/
│  │  │  ├─ security/
│  │  │  ├─ model/
│  │  │  ├─ repository/
│  │  ├─ resources/
│  │  │  ├─ application.propertiesfrontend/
├─ src/
│  ├─ app/
│  │  ├─ components/
│  │  │  ├─ login/
│  │  │  ├─ register/
│  │  ├─ services/
│  │  ├─ guards/
│  ├─ environments/

总结

通过这个教程,我们实现了:
✅ 基于Spring Security的安全认证
✅ JWT令牌的生成与验证
✅ Angular的响应式表单处理
✅ 路由权限控制
✅ 前后端分离架构

扩展建议

  • 添加密码重置功能
  • 实现第三方登录(OAuth2)
  • 增加双因素认证
  • 集成验证码机制

GitHub完整代码
后端代码仓库
前端代码仓库


通过这个全栈解决方案,你可以快速构建安全可靠的用户认证系统,为你的应用奠定坚实的安全基础。欢迎在评论区交流遇到的问题或优化建议!

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

相关文章:

  • 剧本杀小程序系统开发:推动社交娱乐产业创新发展
  • GitCode 7月:小程序积分商城更名成长中心、「探索智能仓颉!Cangjie Magic 体验有奖征文活动」圆满收官、深度对话栏目持续热播
  • qt系统--事件
  • OpenAI推出开源GPT-oss-120b与GPT-oss-20b突破性大模型,支持商用与灵活部署!
  • Numpy科学计算与数据分析:Numpy数组操作入门:合并、分割与重塑
  • 水库大坝安全监测系统主要概述
  • Python 数据类型及数据类型转换
  • Python Socket 脚本深度解析与开发指南
  • 目标检测数据集 - 自动驾驶场景道路异常检测数据集下载「包含VOC、COCO、YOLO三种格式」
  • Jenkins全链路教程——Jenkins用户权限矩阵配置
  • 东莞立晟精密硅胶科技有限公司将携重磅产品亮相 AUTO TECH China 2025 广州国际汽车技术展
  • oracle 11G安装大概率遇到问题
  • 计算机网络:固定网络位长度子网划分flsm和可变长子网掩码划分vlsm的区别
  • QT项目 -仿QQ音乐的音乐播放器(第五节)
  • 全局异常处理器
  • [特殊字符] 未来图钉式 AI 时代的智能生态布局:副脑矩阵与人机共振的系统构想
  • Linux->信号
  • 如何在 VS Code 中进行 `cherry-pick`
  • 计算机毕业设计java疫情防控形势下的高校食堂订餐管理系统 高校食堂订餐管理系统在疫情防控背景下的设计与实现 疫情防控期间高校食堂线上订餐管理平台
  • 【已解决】-bash: mvn: command not found
  • 2025数字马力一面面经(社)
  • [优选算法专题一双指针——两数之和](双指针和哈希表)
  • git branch -a无法查看最新的分支
  • 垃圾桶满溢识别准确率↑32%:陌讯多模态融合算法实战解析
  • 计算机基础·linux系统
  • 一篇文章入门TCP与UDP(保姆级别)
  • Android Auto开发指南
  • KUKA库卡焊接机器人氩气节气设备
  • shell脚本while只循环一次,后续循环失效
  • Android 之 Kotlin 扩展库KTX