Spring Security 的核心職責是認證與授權:
<!-- web.xml -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username;
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
} else {
username = principal.toString();
}
Spring Security 提供兩大核心接口實現自定義用戶/權限加載:
loadUserByUsername(String username),負責從數據庫查詢並構建 UserDetails 對象。@Entity
@Table(name = "sys_user")
public class SysUser implements UserDetails {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "sys_user_role", joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set roles;
// 實現 UserDetails 方法:getAuthorities() 返回角色/權限集合
// isAccountNonExpired、isAccountNonLocked、isCredentialsNonExpired、isEnabled 均返回 true
}
@Entity
@Table(name = "sys_role")
public class SysRole implements GrantedAuthority {
@Id @GeneratedValue
private Long id;
private String name; // e.g. ROLE_ADMIN
private String description;
@Override public String getAuthority() { return name; }
}
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired private UserRepository userRepository;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用戶不存在: " + username);
}
return user; // SysUser 已實現 UserDetails
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private CustomUserDetailsService userDetailsService;
@Autowired private PasswordEncoder passwordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/css/**", "/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll()
.and()
.csrf().disable(); // 簡化演示,生產請啟用 CSRF 保護
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
// 配置方法級表達式處理器等
}
在 Service 方法上使用註解:
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { ... }
@PostAuthorize("returnObject.owner == authentication.name")
public Document findById(Long id) { ... }
通過實現 UserDetailsService 並配合 UserDetails 實體,Spring Security 能無縫對接任意關係型數據庫,實現靈活的認證授權體系。結合方法級安全註解,可實現細粒度的業務權限控制。