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

Spring Security+Angular7 LDAP认证登录功能实现求助

Angular 7 + Spring Boot + Spring Security LDAP 认证完整流程修复指南

看起来你已经搭好了基础框架,但因为前后端分离的适配问题,导致完整登录流程卡壳了。我帮你梳理下问题点,然后一步步修复整个流程:


一、后端Spring Boot配置修复

1. 适配SPA的REST登录(替换原WebSecurity配置)

你原来的formLogin是针对服务器端页面跳转的,而Angular是单页应用,需要返回JSON响应而非页面跳转。修改WebSecurityConfiguration的configure(HttpSecurity http)方法:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .cors() // 开启跨域支持,解决Angular跨域问题
        .and()
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginProcessingUrl("/api/auth/login") // 前端POST请求的登录接口路径
        .usernameParameter("_username_") // 和你之前配置的参数名保持一致
        .passwordParameter("_password_")
        // 登录成功返回JSON
        .successHandler((request, response, authentication) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"status\":\"success\",\"message\":\"登录成功\"}");
        })
        // 登录失败返回JSON
        .failureHandler((request, response, exception) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("{\"status\":\"error\",\"message\":\"" + exception.getMessage() + "\"}");
        })
        .permitAll() // 允许登录接口匿名访问
        .and()
        .logout()
        .logoutUrl("/api/auth/logout")
        .logoutSuccessHandler((request, response, authentication) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"status\":\"success\",\"message\":\"退出成功\"}");
        })
        .and()
        .csrf()
        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

2. 修正LDAP ContextSource的笔误

你原来的contextSource Bean里的Base DN写错了,把cd=org改成dc=org,和application.properties保持一致:

@Bean
public DefaultSpringSecurityContextSource contextSource() {
    return new DefaultSpringSecurityContextSource(Arrays.asList("ldap://localhost:8389/"), "dc=springframework,dc=org");
}

3. 添加CORS配置类

新建一个CORS配置类,允许Angular的域名跨域请求:

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:4200"); // Angular默认运行地址
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

二、前端Angular 7改造

1. 完善登录组件逻辑(login.component.ts)

当前登录页面只有UI,需要添加请求发送和CSRF处理逻辑。首先安装ngx-cookie-service用来读取CSRF Token:

npm install ngx-cookie-service --save

然后编写组件代码:

import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { CookieService } from 'ngx-cookie-service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  username: string = '';
  password: string = '';
  loginStatus: string = '';
  private loginApi = 'http://localhost:8082/api/auth/login';

  constructor(private http: HttpClient, private cookieService: CookieService) { }

  ngOnInit(): void {}

  onLogin(): void {
    // 从Cookie中获取Spring Security生成的CSRF Token
    const xsrfToken = this.cookieService.get('XSRF-TOKEN');
    const headers = new HttpHeaders({
      'Content-Type': 'application/x-www-form-urlencoded',
      'X-XSRF-TOKEN': xsrfToken
    });

    // 构造表单数据,参数名和后端配置一致
    const formData = new FormData();
    formData.append('_username_', this.username);
    formData.append('_password_', this.password);

    // 发送登录请求,withCredentials必须开启才能传递认证Cookie
    this.http.post(this.loginApi, formData, { headers, withCredentials: true })
      .subscribe({
        next: (res: any) => {
          this.loginStatus = res.message;
          // 登录成功后可以跳转到主页,或者通知AppComponent初始化WebSocket
          console.log('登录成功', res);
        },
        error: (err) => {
          this.loginStatus = err.error.message || '登录失败,请检查账号密码';
          console.error('登录失败', err);
        }
      });
  }
}

2. 绑定登录页面UI逻辑

修改login.component.html,把输入框和按钮绑定到组件方法:

<div id="container" fxLayout="column" fxLayoutAlign="start center">
    <div class="spacer" fxFlex="10%"></div>
    <div id="login" fxFlex="25%" fxLayout="column" fxLayoutAlign="start center">
        <h1 id="loginTitle" fxFlex="35%">LOGIN</h1>
        <input 
            id="user" 
            placeholder="username" 
            fxFlex="17.5%" 
            [(ngModel)]="username"
            (keydown.enter)="onLogin()"
        />
        <div class="spacer" fxFlex="10%"></div>
        <input 
            type="password" 
            id="password" 
            placeholder="password" 
            fxFlex="17.5%" 
            [(ngModel)]="password"
            (keydown.enter)="onLogin()"
        />
        <div class="spacer" fxFlex="10%"></div>
        <img 
            id="loginButton" 
            src="../../assets/login/img/right-arrow.png" 
            fxFlex="10%" 
            alt="登录"
            (click)="onLogin()"
            style="cursor: pointer;"
        />
        <div *ngIf="loginStatus" class="status-text" fxFlex="10%">{{ loginStatus }}</div>
    </div>
    <div id="spacer" fxFlex="74%"></div>
    <div id="attention" fxFlex="1%">Icons made by Lyolya</div>
</div>

记得在app.module.ts中导入FormsModule和注册CookieService:

import { FormsModule } from '@angular/forms';
import { CookieService } from 'ngx-cookie-service';

@NgModule({
  imports: [
    // 其他模块...
    FormsModule
  ],
  providers: [CookieService],
  // 其他配置...
})
export class AppModule { }

3. 调整AppComponent的WebSocket逻辑

原来的WebSocket初始化不要在构造函数里执行,应该在登录成功后再启动,避免未认证的连接失败:

import {Component, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
    title = 'Memory';
    status: string = '未登录';
    private serverUrl = 'http://localhost:8082/';
    private stompClient;

    constructor(private http: HttpClient) {}

    ngOnInit() {}

    initializeWebSocketConnection() {
        let ws = new SockJS(this.serverUrl);
        this.stompClient = Stomp.over(ws);
        const that = this;
        this.stompClient.connect({}, 
            (frame) => {
                that.stompClient.subscribe('/chat', (message) => {
                    console.log('收到消息:', message);
                });
                that.status = '已登录';
                setTimeout(() => that.sendMessage('测试消息'), 5000);
            },
            (error) => {
                console.error('WebSocket连接失败:', error);
                that.status = 'WebSocket连接失败';
            }
        );
    }

    sendMessage(msg: string) {
        if (this.stompClient?.connected) {
            this.stompClient.send('/app/send/message', {}, msg);
        } else {
            console.error('请先登录');
        }
    }

    // 供登录组件调用,登录成功后初始化WebSocket
    onLoginSuccess() {
        this.initializeWebSocketConnection();
    }
}

三、关键注意事项

  1. CSRF Token传递:后端配置了CookieCsrfTokenRepository.withHttpOnlyFalse(),所以前端必须从Cookie读取XSRF-TOKEN,并在请求头中携带X-XSRF-TOKEN,否则Spring Security会拒绝请求。
  2. 跨域Credentials:前端请求必须设置withCredentials: true,后端CORS配置要开启allowCredentials(true),这样才能传递认证Cookie。
  3. LDAP用户匹配:确保你的测试LDIF中用户DN符合uid={0},ou=people格式,比如uid=ben,ou=people,dc=springframework,dc=org,登录时输入用户名ben即可。
  4. 密码一致性:后端用的LdapShaPasswordEncoder要求LDAP中的userPassword是SHA加密后的字符串,比如密码password对应的SHA值是{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=。

四、测试流程

  1. 启动Spring Boot应用,确认嵌入式LDAP服务在8389端口正常运行。
  2. 启动Angular应用(ng serve,默认4200端口)。
  3. 访问登录页面,输入LDAP测试账号密码(比如ben/password,根据你的test-server.ldif配置)。
  4. 查看浏览器控制台和后端日志,确认登录请求返回成功JSON。
  5. 登录成功后,WebSocket会自动初始化,测试发送消息验证通信正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:59:34