gpt4 book ai didi

java - 自动自定义认证

转载 作者:搜寻专家 更新时间:2023-10-30 21:34:42 25 4
gpt4 key购买 nike

我想使用 Apache HttpClient 4+ 将经过身份验证的请求发送到 HTTP 服务器(实际上,我需要它用于不同的服务器实现)并且仅在需要时自动进行身份验证(或重新身份验证),当身份验证 token 不存在或已失效

为了进行身份验证,我需要使用包含用户凭据的 JSON 发送 POST 请求。

如果 cookie 中未提供身份验证 token ,一台服务器返回状态代码 401,另一台服务器返回状态代码 500,并在响应正文中包含 AUTH_REQUIRED 文本。

我玩了很多不同的HttpClient版本通过设置 CredentialsProvider使用适当的 Credentials , 试图实现自己的 AuthScheme并注册它并取消注册其余的标准。

我也试过设置自己的AuthenticationHandler .当isAuthenticationRequested叫做我在分析HttpResponse它作为方法参数传递,并通过分析状态代码和响应主体来决定返回什么。我预计这 ( isAuthenticationRequested() == true ) 是强制客户端通过调用 AuthScheme.authenticate 进行身份验证的原因(我的 AuthScheme 实现由 AuthenticationHandler.selectScheme 返回),而不是 AuthScheme.authenticate我可以看到调用 AuthenticationHandler.getChallenges .我真的不知道这个方法应该返回什么,所以我只返回new HashMap<>() .

这是我得到的调试输出结果

DEBUG org.apache.http.impl.client.DefaultHttpClient - Authentication required
DEBUG org.apache.http.impl.client.DefaultHttpClient - example.com requested authentication
DEBUG com.test.httpclient.MyAuthenticationHandler - MyAuthenticationHandler.getChallenges()
DEBUG org.apache.http.impl.client.DefaultHttpClient - Response contains no authentication challenges

接下来我该做什么?我在朝着正确的方向前进吗?

更新

我几乎已经实现了我所需要的。不幸的是,我无法提供完整的项目源代码,因为我无法提供对我的服务器的公共(public)访问。这是我的简化代码示例:

MyAuthScheme.java

public class MyAuthScheme implements ContextAwareAuthScheme {

public static final String NAME = "myscheme";

@Override
public Header authenticate(Credentials credentials,
HttpRequest request,
HttpContext context) throws AuthenticationException {

HttpClientContext clientContext = ((HttpClientContext) context);
String name = clientContext.getTargetAuthState().getState().name();

// Hack #1:
// I've come to this check. I don't like it, but it allows to authenticate
// first request and don't repeat authentication procedure for further
// requests
if(name.equals("CHALLENGED") && clientContext.getResponse() == null) {

//
// auth procedure must be here but is omitted in current example
//

// Hack #2: first request won't be present with auth token cookie set via cookie store
request.setHeader(new BasicHeader("Cookie", "MYAUTHTOKEN=bru99rshi7r5ucstkj1wei4fshsd"));

// this works for second and subsequent requests
BasicClientCookie authTokenCookie = new BasicClientCookie("MYAUTHTOKEN", "bru99rshi7r5ucstkj1wei4fshsd");
authTokenCookie.setDomain("example.com");
authTokenCookie.setPath("/");

BasicCookieStore cookieStore = (BasicCookieStore) clientContext.getCookieStore();
cookieStore.addCookie(authTokenCookie);
}

// I can't return cookie header here, otherwise it will clear
// other cookies, right?
return null;
}

@Override
public void processChallenge(Header header) throws MalformedChallengeException {

}

@Override
public String getSchemeName() {
return NAME;
}

@Override
public String getParameter(String name) {
return null;
}

@Override
public String getRealm() {
return null;
}

@Override
public boolean isConnectionBased() {
return false;
}

@Override
public boolean isComplete() {
return true;
}

@Override
public Header authenticate(Credentials credentials,
HttpRequest request) throws AuthenticationException {
return null;
}

}

MyAuthStrategy.java

public class MyAuthStrategy implements AuthenticationStrategy {

@Override
public boolean isAuthenticationRequested(HttpHost authhost,
HttpResponse response,
HttpContext context) {

return response.getStatusLine().getStatusCode() == 401;
}

@Override
public Map<String, Header> getChallenges(HttpHost authhost,
HttpResponse response,
HttpContext context) throws MalformedChallengeException {

Map<String, Header> challenges = new HashMap<>();
challenges.put(MyAuthScheme.NAME, new BasicHeader(
"WWW-Authentication",
"Myscheme realm=\"My SOAP authentication\""));

return challenges;
}

@Override
public Queue<AuthOption> select(Map<String, Header> challenges,
HttpHost authhost,
HttpResponse response,
HttpContext context) throws MalformedChallengeException {

Credentials credentials = ((HttpClientContext) context)
.getCredentialsProvider()
.getCredentials(new AuthScope(authhost));

Queue<AuthOption> authOptions = new LinkedList<>();
authOptions.add(new AuthOption(new MyAuthScheme(), credentials));

return authOptions;
}

@Override
public void authSucceeded(HttpHost authhost, AuthScheme authScheme, HttpContext context) {}

@Override
public void authFailed(HttpHost authhost, AuthScheme authScheme, HttpContext context) {}

}

MyApp.java

public class MyApp {

public static void main(String[] args) throws IOException {

CredentialsProvider credsProvider = new BasicCredentialsProvider();
Credentials credentials = new UsernamePasswordCredentials("user@example.com", "secret");
credsProvider.setCredentials(AuthScope.ANY, credentials);

HttpClientContext context = HttpClientContext.create();
context.setCookieStore(new BasicCookieStore());
context.setCredentialsProvider(credsProvider);

CloseableHttpClient client = HttpClientBuilder.create()
// my server requires this header otherwise it returns response with code 500
.setDefaultHeaders(Collections.singleton(new BasicHeader("x-requested-with", "XMLHttpRequest")))
.setTargetAuthenticationStrategy(new MyAuthStrategy())
.build();

String url = "https://example.com/some/resource";
String url2 = "https://example.com/another/resource";

// ======= REQUEST 1 =======

HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request, context);
String responseText = EntityUtils.toString(response.getEntity());
request.reset();

// ======= REQUEST 2 =======

HttpGet request2 = new HttpGet(url);
HttpResponse response2 = client.execute(request2, context);
String responseText2 = EntityUtils.toString(response2.getEntity());
request2.reset();

// ======= REQUEST 3 =======

HttpGet request3 = new HttpGet(url2);
HttpResponse response3 = client.execute(request3, context);
String responseText3 = EntityUtils.toString(response3.getEntity());
request3.reset();

client.close();

}

}

版本

http核心:4.4.6
http客户端:4.5.3

可能这不是最好的代码,但至少它有效。

请看我在MyAuthScheme.authenticate()中的评论方法。

最佳答案

对于 Apache HttpClient 4.2,这对我来说是预期的

注意。虽然是用httpclient 4.5编译执行的,但是执行陷入了forever loop。

MyAuthScheme.java

public class MyAuthScheme implements ContextAwareAuthScheme {

public static final String NAME = "myscheme";
private static final String REQUEST_BODY = "{\"login\":\"%s\",\"password\":\"%s\"}";

private final URI loginUri;

public MyAuthScheme(URI uri) {
loginUri = uri;
}

@Override
public Header authenticate(Credentials credentials,
HttpRequest request,
HttpContext context) throws AuthenticationException {

BasicCookieStore cookieStore = (BasicCookieStore) context.getAttribute(ClientContext.COOKIE_STORE);

DefaultHttpClient client = new DefaultHttpClient();

// authentication cookie is set automatically when
// login response arrived
client.setCookieStore(cookieStore);

HttpPost loginRequest = new HttpPost(loginUri);
String requestBody = String.format(
REQUEST_BODY,
credentials.getUserPrincipal().getName(),
credentials.getPassword());
loginRequest.setHeader("Content-Type", "application/json");

try {
loginRequest.setEntity(new StringEntity(requestBody));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

try {
HttpResponse response = client.execute(loginRequest);
int code = response.getStatusLine().getStatusCode();
EntityUtils.consume(response.getEntity());
if(code != 200) {
throw new IllegalStateException("Authentication problem");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
loginRequest.reset();
}

return null;
}

@Override
public void processChallenge(Header header) throws MalformedChallengeException {}

@Override
public String getSchemeName() {
return NAME;
}

@Override
public String getParameter(String name) {
return null;
}

@Override
public String getRealm() {
return null;
}

@Override
public boolean isConnectionBased() {
return false;
}

@Override
public boolean isComplete() {
return false;
}

@Override
public Header authenticate(Credentials credentials,
HttpRequest request) throws AuthenticationException {
// not implemented
return null;
}

}

MyAuthSchemeFactory.java

public class MyAuthSchemeFactory implements AuthSchemeFactory {

private final URI loginUri;

public MyAuthSchemeFactory(URI uri) {
this.loginUri = uri;
}

@Override
public AuthScheme newInstance(HttpParams params) {
return new MyAuthScheme(loginUri);
}

}

MyAuthStrategy.java

public class MyAuthStrategy implements AuthenticationStrategy {

@Override
public boolean isAuthenticationRequested(HttpHost authhost,
HttpResponse response,
HttpContext context) {

return response.getStatusLine().getStatusCode() == 401;
}

@Override
public Map<String, Header> getChallenges(HttpHost authhost,
HttpResponse response,
HttpContext context) throws MalformedChallengeException {

Map<String, Header> challenges = new HashMap<>();
challenges.put("myscheme", new BasicHeader("WWW-Authenticate", "myscheme"));

return challenges;
}

@Override
public Queue<AuthOption> select(Map<String, Header> challenges,
HttpHost authhost,
HttpResponse response,
HttpContext context) throws MalformedChallengeException {

AuthSchemeRegistry registry = (AuthSchemeRegistry) context.getAttribute(ClientContext.AUTHSCHEME_REGISTRY);
AuthScheme authScheme = registry.getAuthScheme(MyAuthScheme.NAME, new BasicHttpParams());
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
Credentials credentials = credsProvider.getCredentials(new AuthScope(authhost));

Queue<AuthOption> options = new LinkedList<>();
options.add(new AuthOption(authScheme, credentials));

return options;
}

@Override
public void authSucceeded(HttpHost authhost, AuthScheme authScheme, HttpContext context) {}

@Override
public void authFailed(HttpHost authhost, AuthScheme authScheme, HttpContext context) {}

}

App.java

public class App {

public static void main(String[] args) throws IOException, URISyntaxException {

URI loginUri = new URI("https://example.com/api/v3/users/login");

AuthSchemeRegistry schemeRegistry = new AuthSchemeRegistry();
schemeRegistry.register(MyAuthScheme.NAME, new MyAuthSchemeFactory(loginUri));

BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope("example.com", 8065),
new UsernamePasswordCredentials("user1@example.com", "secret"));

DefaultHttpClient client = new DefaultHttpClient();
client.setCredentialsProvider(credentialsProvider);
client.setTargetAuthenticationStrategy(new MyAuthStrategy());
client.setAuthSchemes(schemeRegistry);
client.setCookieStore(new BasicCookieStore());


String getResourcesUrl = "https://example.com:8065/api/v3/myresources/";

HttpGet getResourcesRequest = new HttpGet(getResourcesUrl);
getResourcesRequest.setHeader("x-requested-with", "XMLHttpRequest");

try {
HttpResponse response = client.execute(getResourcesRequest);
// consume response
} finally {
getResourcesRequest.reset();
}

// further requests won't call MyAuthScheme.authenticate()

HttpGet getResourcesRequest2 = new HttpGet(getResourcesUrl);
getResourcesRequest2.setHeader("x-requested-with", "XMLHttpRequest");

try {
HttpResponse response2 = client.execute(getResourcesRequest);
// consume response
} finally {
getResourcesRequest2.reset();
}

HttpGet getResourcesRequest3 = new HttpGet(getResourcesUrl);
getResourcesRequest3.setHeader("x-requested-with", "XMLHttpRequest");

try {
HttpResponse response3 = client.execute(getResourcesRequest);
// consume response
} finally {
getResourcesRequest3.reset();
}

}

}

关于java - 自动自定义认证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44034235/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com