2 回答

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 - 無限制

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)
給出的屏幕截圖,在第一次訪問期間
添加服務器發送的證書后。
添加回答
舉報