Spring Security的API Key實(shí)現(xiàn)SpringBoot 接口安全
Spring Security 提供了各種機(jī)制來保護(hù)我們的 REST API。其中之一是 API 密鑰。API 密鑰是客戶端在調(diào)用 API 調(diào)用時(shí)提供的令牌。
在本教程中,我們將討論如何在Spring Security中實(shí)現(xiàn)基于API密鑰的身份驗(yàn)證。
API Keys
一些REST API使用API密鑰進(jìn)行身份驗(yàn)證。API密鑰是一個(gè)標(biāo)記,用于向API客戶端標(biāo)識(shí)API,而無需引用實(shí)際用戶。標(biāo)記可以作為查詢字符串或在請(qǐng)求頭中發(fā)送。
一 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
二 驗(yàn)證請(qǐng)求頭的API KEY
public class AuthenticationService {
private static final String AUTH_TOKEN_HEADER_NAME = "X-API-KEY";
private static final String AUTH_TOKEN = "Baeldung";
public static Authentication getAuthentication(HttpServletRequest request) {
String apiKey = request.getHeader(AUTH_TOKEN_HEADER_NAME);
if ((apiKey == null) || !apiKey.equals(AUTH_TOKEN)) {
throw new BadCredentialsException("Invalid API Key");
}
return new ApiKeyAuthentication(apiKey, AuthorityUtils.NO_AUTHORITIES);
}
}
在這里,我們檢查請(qǐng)求頭是否包含 API Key,如果為空 或者Key值不等于密鑰,那么就拋出一個(gè) BadCredentialsException。如果請(qǐng)求頭包含 API Key,并且驗(yàn)證通過,則將密鑰添加到安全上下文中,然后調(diào)用下一個(gè)安全過濾器。getAuthentication 方法非常簡(jiǎn)單,我們只是比較 API Key 頭部和密鑰是否相等。
為了構(gòu)建 Authentication 對(duì)象,我們必須使用 Spring Security 為了標(biāo)準(zhǔn)身份驗(yàn)證而構(gòu)建對(duì)象時(shí)使用的相同方法。所以,需要擴(kuò)展 AbstractAuthenticationToken 類并手動(dòng)觸發(fā)身份驗(yàn)證。
三 擴(kuò)展AbstractAuthenticationToken
為了成功地實(shí)現(xiàn)我們應(yīng)用的身份驗(yàn)證功能,我們需要將傳入的API Key轉(zhuǎn)換為AbstractAuthenticationToken類型的身份驗(yàn)證對(duì)象。AbstractAuthenticationToken類實(shí)現(xiàn)了Authentication接口,表示一個(gè)認(rèn)證請(qǐng)求的主體和認(rèn)證信息。
public class ApiKeyAuthentication extends AbstractAuthenticationToken {
private final String apiKey;
public ApiKeyAuthentication(String apiKey,
Collection<?extends GrantedAuthority> authorities) {
super(authorities);
this.apiKey = apiKey;
setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return apiKey;
}
}
ApiKeyAuthentication 類是類型為 AbstractAuthenticationToken 的對(duì)象,其中包含從 HTTP 請(qǐng)求中獲取的 apiKey 信息。在構(gòu)造方法中使用 setAuthenticated(true) 方法。因此,Authentication對(duì)象包含 apiKey 和authenticated字段
四 創(chuàng)建自定義過濾器
實(shí)現(xiàn)思路是從請(qǐng)求頭中獲取API Key,然后使用我們的配置檢查秘鑰。在這種情況下,我們需要在Spring Security 配置類中添加一個(gè)自定義的Filter。
我們將從實(shí)現(xiàn)GenericFilterBean開始。GenericFilterBean是一個(gè)基于javax.servlet.Filter接口的簡(jiǎn)單Spring實(shí)現(xiàn)。
public class AuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
try {
Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (Exception exp) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
PrintWriter writer = httpResponse.getWriter();
writer.print(exp.getMessage());
writer.flush();
writer.close();
}
filterChain.doFilter(request, response);
}
}
我們只需要實(shí)現(xiàn)doFilter()方法,在這個(gè)方法中我們從請(qǐng)求頭中獲取API Key,并將生成的Authentication對(duì)象設(shè)置到當(dāng)前的SecurityContext實(shí)例中。
然后請(qǐng)求被傳遞給其余的過濾器處理,接著轉(zhuǎn)發(fā)給DispatcherServlet最后到達(dá)我們的控制器。
五 配置類
通過創(chuàng)建建一個(gè)SecurityFilterChain bean,可以通過編程方式把我們上面編寫的自定義過濾器(Filter)進(jìn)行注冊(cè)。
我們需要在 HttpSecurity 實(shí)例上使用 addFilterBefore() 方法在 UsernamePasswordAuthenticationFilter 類之前添加 AuthenticationFilter。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/**")
.authenticated()
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
六 測(cè)試
- controller
@RestController
public class ResourceController {
@GetMapping("/home")
public String homeEndpoint() {
return "Baeldung !";
}
}
- 啟動(dòng)類
禁用 Auto-Configuration
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
public class ApiKeySecretAuthApplication {
public static void main(String[] args) {
SpringApplication.run(ApiKeySecretAuthApplication.class, args);
}
}
- 測(cè)試
curl --location --request GET 'http://localhost:8080/home'
結(jié)果返回401
請(qǐng)求頭中加上API Key后,再次請(qǐng)求文章來源:http://www.zghlxwxcb.cn/news/detail-840200.html
curl --location --request GET 'http://localhost:8080/home' \
--header 'X-API-KEY: Baeldung'
結(jié)果返回200文章來源地址http://www.zghlxwxcb.cn/news/detail-840200.html
到了這里,關(guān)于Spring Security的API Key實(shí)現(xiàn)SpringBoot 接口安全的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!