在當今的網路環境中,保障 RESTful API 的安全性變得越來越重要。無論是企業應用還是個人專案,保護你的 API 免受未經授權的訪問與攻擊都是開發過程中的一個重要課題
在使用 Spring Security 保護 RESTful API 之前,首先需要在你的 Spring Boot 專案中添加相關的依賴。在 pom.xml 中添加如下依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
在 RESTful API 中,最常見的身份驗證方式是基本身份驗證。你可以通過覆寫 configure 方法來設定基本身份驗證
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("{noop}password") // {noop}表示不加密
.roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // 禁用 CSRF,適用於 RESTful API
.authorizeRequests()
.anyRequest().authenticated() // 所有請求都需要認證
.and()
.httpBasic(); // 啟用基本身份驗證
}
}
JWT 是目前非常流行的一種身份驗證方式。相較於基本身份驗證,JWT 更加靈活且安全。以下是使用 JWT 的基本實作
在 pom.xml 中加入 JWT 的依賴
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
首先,創建一個 JWT 工具類來生成與驗證令牌
@Component
public class JwtTokenUtil {
private final String SECRET_KEY = "your_secret_key"; // 請務必更改此值
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 小時後過期
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public Claims extractClaims(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
public String extractUsername(String token) {
return extractClaims(token).getSubject();
}
public boolean isTokenExpired(String token) {
return extractClaims(token).getExpiration().before(new Date());
}
public boolean validateToken(String token, String username) {
return (extractUsername(token).equals(username) && !isTokenExpired(token));
}
}
接下來,創建一個過濾器來攔截請求並驗證 JWT
public class JwtRequestFilter extends WebAuthenticationFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtTokenUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// 驗證邏輯
}
chain.doFilter(request, response);
}
}
根據不同的角色或權限限制 API 存取,例如使用以下程式碼設定 API 的端點
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // 只有 ADMIN 角色可以訪問
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN") // USER 和 ADMIN 都可以訪問
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
在 RESTful API 中,通常建議禁用 CSRF 保護,因為大多數 API 是無狀態的。然而,如果你的 API 需要 CSRF 保護,可以使用以下程式碼啟用
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
為了允許從不同來源進行訪問,你可以設定 CORS
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
};
}
使用 Spring Security 來保護你的 RESTful API 是一個明智的選擇。通過實施身份驗證、授權、CSRF 保護和 CORS 設定,你的 API 將能夠抵禦大多數潛在的安全威脅