您是否考虑过使用基于 OAuth 的身份验证和 API 密钥管理来保护您的 API。从security perspective 来看,HTTP 基本身份验证并不理想,用户名和密码还有另一组 security issues for APIs
无论哪种方式,您都可以考虑使用Stormpath 来让这对您来说真的很容易。看看this guide,它同时支持HTTP basic和OAuth。
此示例代码将让您清楚地了解这是多么容易。
假设您想要公开一个名为startEngines() 的操作并且您想要保护它。您还需要公开一个新操作以获取 访问令牌,在此示例中为 String getAccessToken(ApiKey)。
您的用户将运行如下内容:
@Test
public void executeSomeOauth2AuthenticatedOperation() {
String userApiKeyPath = System.getProperty("user.home") + "/.stormpath/apiKey_4Yrc0TJ5sBFldwtu6nfzf5.properties";
ApiKey userApiKey = ApiKeys.builder().setFileLocation(userApiKeyPath).build();
//Developer requests access token
String accessToken = getAccessToken(userApiKey);
//Developer executes an authenticated operation (e.g startEngines()) with the provided accessToken
if (startEngines(accessToken)) {
System.out.print("Client-side message: Execution allowed");
} else {
System.out.print("Client-side message: Execution denied");
}
}
您的代码将如下所示:
String path = System.getProperty("user.home") + "/.stormpath/apiKey.properties";
String applicationUrl = "https://api.stormpath.com/v1/applications/2TqboZ1qo73eDM4gTo2H94";
Client client = Clients.builder().setApiKey(ApiKeys.builder().setFileLocation(path).build()).build();
Application application = client.getResource(applicationUrl, Application.class);
public String getAccessToken(ApiKey apiKey) {
HttpRequest request = createOauthAuthenticationRequest(apiKey);
AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
System.out.println(accessTokenResult.getScope());
return accessTokenResult.getTokenResponse().getAccessToken();
}
public boolean startEngines(String accessToken) {
HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
try {
OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
System.out.println(result.getAccount().getEmail() + " is about to start the engines!");
doStartEngines(); //Here you will actually call your internal doStartEngines() operation
return true;
} catch (AccessTokenOauthException e) {
//This accessToken is not allowed to start the engines
System.out.print("AccessToken: " + accessToken + " just tried to start the engines. He is not allowed to do so.");
return false;
}
}
private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) {
try {
String credentials = apiKey.getId() + ":" + apiKey.getSecret();
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Content-Type", new String[]{"application/x-www-form-urlencoded"});
headers.put("Authorization", new String[]{"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8"))});
Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
parameters.put("grant_type", new String[]{"client_credentials"});
HttpRequest request = HttpRequests.method(HttpMethod.POST)
.headers(headers)
.parameters(parameters)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
try {
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Authorization", new String[]{"Bearer " + token});
HttpRequest request = HttpRequests.method(HttpMethod.GET)
.headers(headers)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void doStartEngines() {
System.out.println("Server-side message: Engines started!!!");
}
为了简单起见,我让所有这些代码在同一台机器上运行(客户端和服务器端代码之间没有网络通信)。您实际上需要使用 Spring 通过 Rest API 公开 startEngines() 和 String getAccessToken(ApiKey),并让最终用户通过网络访问它们。
试一试,它应该是一个非常简单快捷的解决方案。 :)
完全披露-我在Stormpath工作