亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Spring Boot - 需要 api 密鑰和 x509,但不適用于所有端點

Spring Boot - 需要 api 密鑰和 x509,但不適用于所有端點

慕斯709654 2023-07-19 10:53:02
Java 11、Spring 啟動 2.1.3、Spring 5.1.5我有一個 Spring Boot 項目,其中某些端點由 API 密鑰保護。目前使用以下代碼效果很好:@Component("securityConfig")@ConfigurationProperties("project.security")@EnableWebSecurity@Order(1)public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {? ? private static final Logger LOG = LoggerFactory.getLogger(SecurityJavaConfig.class);? ? private static final String API_KEY_HEADER = "x-api-key";? ? private String apiKey;? ? @Override? ? protected void configure(HttpSecurity httpSecurity) throws Exception {? ? ? ? APIKeyFilter filter = new APIKeyFilter(API_KEY_HEADER);? ? ? ? filter.setAuthenticationManager(authentication -> {? ? ? ? ? ? String apiKey = (String) authentication.getPrincipal();? ? ? ? ? ? if (this.apiKey != null && !this.apiKey.isEmpty() && this.apiKey.equals(apiKey)) {? ? ? ? ? ? ? ? authentication.setAuthenticated(true);? ? ? ? ? ? ? ? return authentication;? ? ? ? ? ? } else {? ? ? ? ? ? ? ? throw new BadCredentialsException("Access Denied.");? ? ? ? ? ? }? ? ? ? });? ? ? ? httpSecurity? ? ? ? ? ? .antMatcher("/v1/**")? ? ? ? ? ? .csrf()? ? ? ? ? ? .disable()? ? ? ? ? ? .sessionManagement()? ? ? ? ? ? .sessionCreationPolicy(SessionCreationPolicy.STATELESS)? ? ? ? ? ? .and()? ? ? ? ? ? .addFilter(filter)? ? ? ? ? ? .authorizeRequests()? ? ? ? ? ? .anyRequest()? ? ? ? ? ? .authenticated();? ? }}這成功地需要一個包含 API 密鑰的標頭,但僅適用于以下端點:/v1/...我有一個新的要求,需要證書進行身份驗證。我按照以下指南在我的項目中進行了 X.509 身份驗證設置:禿頂迪區以代碼為中心但是,我遇到了一些問題:證書始終是必需的,而不僅僅是/v1/*端點API 密鑰過濾器不再起作用
查看完整描述

2 回答

?
一只名叫tom的貓

TA貢獻1906條經驗 獲得超3個贊

在您的要求中,由于沒有角色(不同的客戶端具有不同的訪問級別),因此不需要 UserDetailService
APIKeyFilter 足以與 X509 和 API 密鑰配合使用。

考慮APIKeyFilter擴展X509AuthenticationFilter,如果存在沒有有效證書的請求,則過濾器鏈將被破壞,并且將發送403/的錯誤響應。 如果證書有效,則過濾器鏈繼續并進行身份驗證。而驗證我們所擁有的只有來自身份驗證對象的兩個方法 - - 。其中主題是 (EMAIL=, CN=, OU=, O=, L=, ST=, C=) (APIKeyFilter 應配置為返回主體和憑證對象) 您可以使用主體(您的 API 密鑰)來驗證 api 密鑰由客戶發送。您 可以使用憑據(證書主題)作為增強功能來單獨識別每個客戶端,如果需要,您可以為不同的客戶端授予不同的權限。Forbidden

getPrincipal()header:"x-api-key"
getCredential()certificate subject


回顧您的要求
1. API V1 - 僅當證書和 API 密鑰有效時才可訪問。
2. 其他API - 無限制


查看完整回答
反對 回復 2023-07-19
?
繁星淼淼

TA貢獻1775條經驗 獲得超11個贊

public class APIKeyFilter extends X509AuthenticationFilter

{

    private String principalRequestHeader;


    public APIKeyFilter(String principalRequestHeader) 

    {

        this.principalRequestHeader = principalRequestHeader;

    }


    @Override

    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request)

    {

        return request.getHeader(principalRequestHeader);

    }


    @Override

    protected Object getPreAuthenticatedCredentials(HttpServletRequest request)

    {

        X509Certificate[] certs = (X509Certificate[]) request

                .getAttribute("javax.servlet.request.X509Certificate");


        if(certs.length > 0)

        {

            return certs[0].getSubjectDN();

        }


        return super.getPreAuthenticatedCredentials(request);

    }

}

@Configuration

@EnableWebSecurity

public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {


    private static final String API_KEY_HEADER = "x-api-key";


    private String apiKey = "SomeKey1234567890";


    @Override

    protected void configure(HttpSecurity http) throws Exception 

    {

        APIKeyFilter filter = new APIKeyFilter(API_KEY_HEADER);

        filter.setAuthenticationManager(authentication -> {

            if(authentication.getPrincipal() == null) // required if you configure http

            {

                throw new BadCredentialsException("Access Denied.");

            }

            String apiKey = (String) authentication.getPrincipal();

            if (authentication.getPrincipal() != null && this.apiKey.equals(apiKey)) 

            {

                authentication.setAuthenticated(true);

                return authentication;

            }

            else

            {

                throw new BadCredentialsException("Access Denied.");

            }

        });


        http.antMatcher("/v1/**")

                .csrf().disable()

                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

            .and()

                .addFilter(filter)

                .authorizeRequests()

                .anyRequest()

                .authenticated();

    }


    @Bean

    public PasswordEncoder passwordEncoder() 

    {

        return new BCryptPasswordEncoder();

    }

}

驗證 API 響應

https - 用于數據加密(服務器向客戶端發送的 ssl 證書)

X509 - 用于客戶端識別(使用服務器 ssl 證書生成的 ssl 證書,但不同客戶端不同)

API key - 用于安全檢查的共享密鑰。


出于驗證目的,假設您有 3 個版本,如下所示


@RestController

public class HelloController

{

    @RequestMapping(path = "/v1/hello")

    public String helloV1()

    {

        return "HELLO Version 1";

    }


    @RequestMapping(path = "/v0.9/hello")

    public String helloV0Dot9()

    {

        return "HELLO Version 0.9";

    }


    @RequestMapping(path = "/v0.8/hello")

    public String helloV0Dot8()

    {

        return "HELLO Version 0.8";

    }

}

下面給出不同情況下的響應。

CASE 1.a 版本 1,標頭中包含有效的 X509 和 API 密鑰


curl -ik --cert pavel.crt --key myPrivateKey.pem -H "x-api-key:SomeKey1234567890" "https://localhost:8443/v1/hello"

回復


HTTP/1.1 200

HELLO Version 1

CASE 1.b 版本 1 僅適用于 X509(無 API 密鑰)

curl -ik --cert pavel.crt --key myPrivateKey.pem "https://localhost:8443/v1/hello"

回復


HTTP/1.1 403

{"timestamp":"2019-09-13T11:53:29.269+0000","status":403,"error":"Forbidden","message":"Access Denied","path":"/v1/hello"}

注意:

在您的情況下,有兩種類型的證書

i。帶有 X509 的客戶端證書

ii:如果客戶端不包含證書,則將使用服務器中使用的數據交換證書,即不帶 X509 的證書

2. 版本 X 不帶 X509,標頭中不帶 API 密鑰。


curl "https://localhost:8443/v0.9/hello"

如果服務器證書是自簽名證書(沒有 CA 即證書頒發機構,證書無效)


curl performs SSL certificate verification by default, using a "bundle"

 of Certificate Authority (CA) public keys (CA certs). If the default

 bundle file isn't adequate, you can specify an alternate file

 using the --cacert option.

If this HTTPS server uses a certificate signed by a CA represented in

 the bundle, the certificate verification probably failed due to a

 problem with the certificate (it might be expired, or the name might

 not match the domain name in the URL).

If you'd like to turn off curl's verification of the certificate, use

 the -k (or --insecure) option.

如果服務器 SSL 證書有效(CA 認證)則

curl "https://localhost:8443/v0.9/hello"

你好版本0.9


curl "https://localhost:8443/v0.8/hello"

你好版本0.8


注意:如果您在開發環境中沒有 CA 認證的 SSL 證書,請測試 Hack

使用服務器證書(.crt)和serverPrivateKey(.pem 文件)以及請求,如下所示


curl -ik --cert server.crt --key serverPrivateKey.pem "https://localhost:8443/v0.9/hello"

這也可以在 Mozilla 中進行驗證(對于自簽名證書),并且可以在 google chrome 中進行相同的驗證(如果 CA 認證的 SSL)

給出的屏幕截圖,在第一次訪問期間

http://img1.sycdn.imooc.com//64b7504b00014c1c06530428.jpg

添加服務器發送的證書后。

http://img1.sycdn.imooc.com//64b7505600014dcc05190133.jpg


查看完整回答
反對 回復 2023-07-19
  • 2 回答
  • 0 關注
  • 210 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號