首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

基於 Spring + Acegi (Spring Security) 的企業級權限控制系統設計與實現

     編輯:Java 程式設計入門

Spring 框架雖提供優秀的 IoC/AOP 基礎設施,但本身不包含安全模塊。早期社區通過 Acegi Security(現已更名為 Spring Security)填補此空白。本文基於 Spring Security 現代架構(以 5.x/6.x 為準),系統闡述認證授權核心流程、數據庫擴展設計、攔截器配置、方法級安全、以及遷移建議,助你構建生產級權限控制體系。

一、 核心架構:三大支柱

┌─────────────────────────────────────┐
│         Security Filter Chain        │  (Servlet Filter 鏈,入口防護)
├─────────────────────────────────────┤
│  AuthenticationManager               │  認證管理器:驗證身份
│   └─ ProviderManager                 │     ├─ DaoAuthenticationProvider (DB)
│                                      │     ├─ LdapAuthenticationProvider
│                                      │     └─ JwtAuthenticationProvider (自定義)
├─────────────────────────────────────┤
│  AccessDecisionManager               │  授權決策管理器:判定權限
│   ├─ AffirmativeBased (一票通過)      │
│   ├─ ConsensusBased (少數服從多數)    │
│   └─ UnanimousBased (全票通過)       │
└─────────────────────────────────────┘

二、 數據庫擴展設計:RBAC + 資源綁定

Acegi 原始 users/authorities 兩表過於簡陋,引入 角色 與 資源 概念,支持細粒度控制。

ER 關係

sys_user (id, username, password, enabled, ...)
    │
    ├─ sys_user_role (user_id, role_id)
    │       │
    │       └─ sys_role (id, code, name, description)
    │               │
    │               └─ sys_role_permission (role_id, perm_id)
    │                       │
    │                       └─ sys_permission (id, code, name, type[URL/FUNC], pattern, method)
    │
    └─ sys_user_permission (user_id, perm_id)  -- 用戶直授權(補充)

關鍵表結構

表名核心字段說明
sys_userid, username, password, salt, enabled, locked, expire_time用戶主表,密碼存 BCrypt 雜湊
sys_roleid, code, name, description, enabled角色表,code 如 ROLE_ADMIN
sys_permissionid, code, name, type, pattern, http_method, description權限/資源表,type: 1=URL, 2=方法
sys_user_roleuser_id, role_id用戶-角色多對多
sys_role_permissionrole_id, perm_id角色-權限多對多

三、 認證體系配置

3.1 UserDetailsService 實現

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired private UserMapper userMapper;
    @Autowired private PermissionMapper permMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser user = userMapper.selectByUsername(username);
        if (user == null) throw new UsernameNotFoundException("用戶不存在");

        // 查詢用戶權限碼集合
        List<String> permCodes = permMapper.selectPermCodesByUserId(user.getId());
        List<GrantedAuthority> authorities = permCodes.stream()
            .map(SimpleGrantedAuthority::new)
            .collect(Collectors.toList());

        return new org.springframework.security.core.userdetails.User(
            user.getUsername(), user.getPassword(), user.isEnabled(),
            true, true, true, authorities);
    }
}

3.2 PasswordEncoder 與 AuthenticationManager

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(10); // 強度 10
    }

    @Bean
    public AuthenticationManager authenticationManager(
            AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

    @Bean
    public DaoAuthenticationProvider daoAuthProvider(CustomUserDetailsService uds,
                                                     PasswordEncoder encoder) {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(uds);
        provider.setPasswordEncoder(encoder);
        // 可選:緩存
        // provider.setUserCache(new SpringCacheBasedUserCache(cacheManager));
        return provider;
    }
}

四、 授權體系配置

4.1 Web 安全:FilterSecurityInterceptor 鏈

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/login", "/css/**", "/js/**").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .requestMatchers(HttpMethod.GET, "/api/users/**").hasAuthority("USER_QUERY")
            .anyRequest().authenticated()
        )
        .formLogin(form -> form
            .loginPage("/login").permitAll()
            .defaultSuccessUrl("/index")
        )
        .logout(logout -> logout.logoutSuccessUrl("/login"))
        .csrf(csrf -> csrf.ignoringRequestMatchers("/api/**")) // API 通常無狀態
        .sessionManagement(sess -> sess.maximumSessions(1)); // 同步登錄控制

    return http.build();
}

4.2 方法級安全:@PreAuthorize / @Secured

@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfig {}

@Service
public class OrderService {

    @PreAuthorize("hasAuthority('ORDER_CREATE')")
    public Order create(OrderDTO dto) { ... }

    @PreAuthorize("hasAuthority('ORDER_DELETE') and #order.owner == authentication.name")
    public void delete(Long orderId) { ... }

    @Secured("ROLE_ADMIN")
    public void adminOnly() { ... }
}

4.3 動態權限決策:自定義 AccessDecisionManager

@Component
public class DynamicAccessDecisionManager implements AccessDecisionManager {

    @Autowired private PermissionMapper permMapper;

    @Override
    public void decide(Authentication auth, Object object,
                       Collection<ConfigAttribute> configAttrs) {
        // 從數據庫實時加載當前請求 URL 所需權限碼
        // 與用戶 authorities 比對
        // 不滿足拋出 AccessDeniedException
    }

    @Override public boolean supports(ConfigAttribute attr) { return true; }
    @Override public boolean supports(Class<?> clazz) { return true; }
}

五、 遺留 Acegi 遷移指南

Acegi (舊)Spring Security (新)備註
net.sf.acegisecurity.*org.springframework.security.*包名全變
AuthenticationDaoUserDetailsService接口更名
AutoIntegrationFilterSecurityContextPersistenceFilterFilter 鏈重構
FilterSecurityInterceptor (XML bean)SecurityFilterChain (DSL)配置方式變革
MethodDefinitionMap / DBFilterInvocationDefinitionSource@PreAuthorize / MethodSecurityInterceptor方法級安全註解化
jdbcDaoImpl + XML SQLJdbcUserDetailsManager / 自定義 UserDetailsService更靈活

六、 最佳實踐清單

  • 密碼存儲:強制 BCrypt/Argon2,禁用 MD5/SHA1/明文。
  • 會話管理:並發會話控制、會話固定攻擊防護、Remember-Me 加密 Token。
  • CSRF 策略:瀏覽器表單開啟,REST API 關閉(改用 Stateless JWT/OAuth2)。
  • 權限緩存:Redis 緩存用戶權限碼,登出/權限變更時主動失效。
  • 審計日誌:實現 AuthenticationSuccessEventListener、AuthorizationAuditListener 記錄關鍵操作。
  • 測試驗證:@WithMockUser、@WithAnonymousUser 單元測試覆蓋關鍵授權點。

從 Acegi 到 Spring Security,核心思想未變:認證確認「你是誰」,授權決定「你能幹什麼」。現代 Spring Security 以 DSL 配置、註解驅動、響應式支持、OAuth2/JWT 整合,將安全從「XML 地獄」解放為「代碼即配置」的工程實踐。掌握其 Filter 鏈機制、Authentication/Authorization 雙引擎、以及與業務數據模型的映射關係,即可構建既符合合規要求、又具備極高擴展性的企業級權限控制系統。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved