非Spring Boot/Web的JavaFX桌面应用集成Spring Security方案咨询
在非Spring Boot的JavaFX桌面应用中集成Spring Security
1. 引入核心依赖
因为不是Spring Boot/Web应用,仅需引入Spring Security核心模块和Spring上下文依赖(用于Bean管理),以Maven为例:
<dependencies> <!-- Spring Security 核心 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>5.7.11</version> <!-- 选择合适的稳定版本 --> </dependency> <!-- Spring 上下文 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.29</version> </dependency> </dependencies>
2. 初始化Spring容器与Security配置
手动创建Spring配置类,定义Security核心Bean:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级权限注解支持 public class SecurityConfig { // 密码编码器 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 用户信息服务(示例用内存存储,实际可替换为数据库查询) @Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("admin") .password(passwordEncoder().encode("admin123")) .roles("ADMIN") .build()); manager.createUser(User.withUsername("user") .password(passwordEncoder().encode("user123")) .roles("USER") .build()); return manager; } // 认证管理器 @Bean public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder()); return auth.build(); } }
在JavaFX应用启动时初始化Spring容器:
import javafx.application.Application; import javafx.stage.Stage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainApp extends Application { private static AnnotationConfigApplicationContext springContext; @Override public void init() throws Exception { // 初始化Spring容器 springContext = new AnnotationConfigApplicationContext(SecurityConfig.class); } @Override public void start(Stage primaryStage) throws Exception { // 加载登录界面 LoginController loginController = springContext.getBean(LoginController.class); loginController.showLoginWindow(primaryStage); } @Override public void stop() throws Exception { // 关闭Spring容器 springContext.close(); } public static AnnotationConfigApplicationContext getSpringContext() { return springContext; } public static void main(String[] args) { launch(args); } }
3. 实现登录认证逻辑
在JavaFX登录控制器中,注入AuthenticationManager处理登录请求:
import javafx.fxml.FXML; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.stage.Stage; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; public class LoginController { private final AuthenticationManager authenticationManager; // 构造注入AuthenticationManager(Spring自动完成) public LoginController(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @FXML private TextField usernameField; @FXML private PasswordField passwordField; @FXML private void handleLogin() { String username = usernameField.getText(); String password = passwordField.getText(); try { // 执行认证 Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(username, password) ); // 将认证信息存入SecurityContext SecurityContextHolder.getContext().setAuthentication(authentication); // 登录成功跳转主界面 openMainWindow(); closeLoginWindow(); } catch (AuthenticationException e) { // 认证失败提示错误 showError("登录失败:" + e.getMessage()); } } // 界面跳转辅助方法,根据实际FXML调整 private void openMainWindow() { // 加载主界面逻辑 } private void closeLoginWindow() { ((Stage) usernameField.getScene().getWindow()).close(); } private void showError(String message) { // 弹出错误提示 } }
4. 实现授权控制
方法级授权
在业务Bean上使用@PreAuthorize注解控制方法调用权限:
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; @Service public class UserService { // 仅ADMIN角色可调用 @PreAuthorize("hasRole('ADMIN')") public void deleteUser(String userId) { // 删除用户逻辑 } // USER或ADMIN角色均可调用 @PreAuthorize("hasAnyRole('USER', 'ADMIN')") public void viewUser(String userId) { // 查看用户逻辑 } }
UI层面权限控制
在JavaFX控制器中,根据当前用户权限动态显示/隐藏控件:
import javafx.fxml.FXML; import javafx.scene.control.Button; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.authority.SimpleGrantedAuthority; public class MainController { @FXML private Button deleteUserBtn; @FXML public void initialize() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // 判断是否拥有ADMIN权限,无权限则隐藏删除按钮 boolean isAdmin = auth.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN")); deleteUserBtn.setVisible(isAdmin); } }
5. 会话状态维护
- 应用退出时清除SecurityContext:
@Override public void stop() throws Exception { SecurityContextHolder.clearContext(); springContext.close(); }
- 页面切换时,可通过
SecurityContextHolder.getContext().getAuthentication()获取当前用户信息,重复权限校验逻辑。
内容的提问来源于stack exchange,提问作者Ali Akbar Ahmadi
相关产品推荐
相关产品推荐

