<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot接口安全快試試用 API Key 來保護(hù)吧

          共 10969字,需瀏覽 22分鐘

           ·

          2024-04-11 21:36

          星標(biāo)Java學(xué)習(xí)之道一起成長,一起學(xué)習(xí)~

          目錄

          • 1、概述
          • 2、REST API Security
          • 3、用API Keys保護(hù)REST API
          • 4、測試
          文章來源: https://www.baeldung.com/spring-boot-api-key-secret

          1、概述

          安全性在REST API開發(fā)中扮演著重要的角色。一個不安全的REST API可以直接訪問到后臺系統(tǒng)中的敏感數(shù)據(jù)。因此,企業(yè)組織需要關(guān)注API安全性。

          Spring Security 提供了各種機(jī)制來保護(hù)我們的 REST API。其中之一是 API 密鑰。API 密鑰是客戶端在調(diào)用 API 調(diào)用時提供的令牌。

          在本教程中,我們將討論如何在Spring Security中實(shí)現(xiàn)基于API密鑰的身份驗(yàn)證。

          2、REST API Security

          Spring Security可以用來保護(hù)REST API的安全性。REST API是無狀態(tài)的,因此不應(yīng)該使用會話或cookie。相反,應(yīng)該使用Basic authentication,API Keys,JWT或OAuth2-based tokens來確保其安全性。

          2.1. Basic Authentication

          Basic authentication是一種簡單的認(rèn)證方案??蛻舳税l(fā)送HTTP請求,其中包含Authorization標(biāo)頭的值為Basic base64_url編碼的用戶名:密碼。Basic authentication僅在HTTPS / SSL等其他安全機(jī)制下才被認(rèn)為是安全的。

          2.2. OAuth2

          OAuth2是REST API安全的行業(yè)標(biāo)準(zhǔn)。它是一種開放的認(rèn)證和授權(quán)標(biāo)準(zhǔn),允許資源所有者通過訪問令牌將授權(quán)委托給客戶端,以獲得對私有數(shù)據(jù)的訪問權(quán)限。

          2.3. API Keys

          一些REST API使用API密鑰進(jìn)行身份驗(yàn)證。API密鑰是一個標(biāo)記,用于向API客戶端標(biāo)識API,而無需引用實(shí)際用戶。標(biāo)記可以作為查詢字符串或在請求頭中發(fā)送。

          3、用API Keys保護(hù)REST API

          3.1  添加Maven 依賴

          讓我們首先在我們的pom.xml中聲明spring-boot-starter-security依賴關(guān)系:

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-security</artifactId>
          </dependency>

          3.2 創(chuàng)建自定義過濾器(Filter)

          實(shí)現(xiàn)思路是從請求頭中獲取API Key,然后使用我們的配置檢查秘鑰。在這種情況下,我們需要在Spring Security 配置類中添加一個自定義的Filter。

          我們將從實(shí)現(xiàn)GenericFilterBean開始。GenericFilterBean是一個基于javax.servlet.Filter接口的簡單Spring實(shí)現(xiàn)。

          讓我們創(chuàng)建AuthenticationFilter類:

          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()方法,在這個方法中我們從請求頭中獲取API Key,并將生成的Authentication對象設(shè)置到當(dāng)前的SecurityContext實(shí)例中。

          然后請求被傳遞給其余的過濾器處理,接著轉(zhuǎn)發(fā)給DispatcherServlet最后到達(dá)我們的控制器。

          在AuthenticationService類中,實(shí)現(xiàn)從Header中獲取API Key并構(gòu)造Authentication對象,代碼如下:

          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);
              }
          }

          在這里,我們檢查請求頭是否包含 API Key,如果為空 或者Key值不等于密鑰,那么就拋出一個 BadCredentialsException。如果請求頭包含 API Key,并且驗(yàn)證通過,則將密鑰添加到安全上下文中,然后調(diào)用下一個安全過濾器。getAuthentication 方法非常簡單,我們只是比較 API Key 頭部和密鑰是否相等。

          為了構(gòu)建 Authentication 對象,我們必須使用 Spring Security 為了標(biāo)準(zhǔn)身份驗(yàn)證而構(gòu)建對象時使用的相同方法。所以,需要擴(kuò)展 AbstractAuthenticationToken 類并手動觸發(fā)身份驗(yàn)證。

          3.3. 擴(kuò)展AbstractAuthenticationToken

          為了成功地實(shí)現(xiàn)我們應(yīng)用的身份驗(yàn)證功能,我們需要將傳入的API Key轉(zhuǎn)換為AbstractAuthenticationToken類型的身份驗(yàn)證對象。AbstractAuthenticationToken類實(shí)現(xiàn)了Authentication接口,表示一個認(rèn)證請求的主體和認(rèn)證信息。

          讓我們創(chuàng)建ApiKeyAuthentication類:

          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 的對象,其中包含從 HTTP 請求中獲取的 apiKey 信息。在構(gòu)造方法中使用 setAuthenticated(true) 方法。因此,Authentication對象包含 apiKey 和authenticated字段:

          3.4. Security Config

          通過創(chuàng)建建一個SecurityFilterChain bean,可以通過編程方式把我們上面編寫的自定義過濾器(Filter)進(jìn)行注冊。

          我們需要在 HttpSecurity 實(shí)例上使用 addFilterBefore() 方法在 UsernamePasswordAuthenticationFilter 類之前添加 AuthenticationFilter。

          創(chuàng)建SecurityConfig 類:

          @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();
              }

          }

          此外注意代碼中我們吧繪畫策略(session policy)設(shè)置為無狀態(tài)(STATELESS),因?yàn)槲覀兪褂玫氖荝EST。歡迎關(guān)注公眾號"Java學(xué)習(xí)之道",查看更多干貨!

          3.5. ResourceController

          最后,我們創(chuàng)建ResourceController,實(shí)現(xiàn)一個Get請求  /home

          @RestController
          public class ResourceController {
              @GetMapping("/home")
              public String homeEndpoint() {
                  return "Baeldung !";
              }
          }
          3.6. 禁用 Auto-Configuration
          @SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
          public class ApiKeySecretAuthApplication {

              public static void main(String[] args) {
                  SpringApplication.run(ApiKeySecretAuthApplication.class, args);
              }
          }

          4、測試

          4.1、我們先不提供API Key進(jìn)行測試

          curl --location --request GET 'http://localhost:8080/home'

          返回 401 未經(jīng)授權(quán)錯誤。

          4.2、請求頭中加上API Key后,再次請求

          curl --location --request GET 'http://localhost:8080/home' \
          --header 'X-API-KEY: Baeldung'

          請求返回狀態(tài)200

          4.3、源碼地址:

          https://github.com/eugenp/tutorials/tree/master/spring-security-modules/spring-security-web-boot-4
          -- END --
               
                      

          如果看到這里,說明你喜歡這篇文章,那就轉(zhuǎn)發(fā)、點(diǎn)贊、在看三連吧。如果你有任何疑問,也歡迎找我溝通和交流。

          加我微信,交個朋友
                     
          長按/掃碼添加↑↑↑

          瀏覽 38
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码一区二区三区四区五区 | 天天操天天摸天天爱 | 加勒比久久综合 | 97国产在线观看 | 操人妻网|