如何从Android访问Bearer认证服务

3

我将使用一个采用Bearer身份验证的服务。我尝试从Android获取它,但没有成功。以下是我的代码。

String mytoken = "some token I am sure is right";
HttpClient witClient = new DefaultHttpClient();
Uri.Builder b = Uri.parse("www.somewebsite.com").buildUpon();
b.appendQueryParameter("q", "some query string");
String finalurl = b.build().toString();
HttpGet request = new HttpGet(new URI(finalurl));
request.setHeader("Authorization", "Bearer "+mytoken);
HttpResponse response = witClient.execute(request);

服务器会返回一个错误,说需要进行身份验证。显然,头信息被某种方式丢失了。
11-22 21:50:42.180: W/DefaultRequestDirector(3408): Authentication error: Unable to respond to any of these challenges: {bearer=Www-Authenticate: Bearer realm="OAuth required"}

哪里出错了

1个回答

8
这可能有点复杂,但我已经成功地完成了它,所以我会尝试分享我的经验。您需要提供以下几项:
  • org.apache.http.auth.Credentials的实现
  • org.apache.http.auth.AuthSchemeFactory的实现
您的Credentials实现应该类似于以下内容:
import java.security.Principal;

import org.apache.http.auth.BasicUserPrincipal;
import org.apache.http.auth.Credentials;

public class TokenCredentials implements Credentials {
    private Principal userPrincipal;

    public TokenCredentials(String token) {
        this.userPrincipal = new BasicUserPrincipal(token);
    }

    @Override
    public Principal getUserPrincipal() {
        return userPrincipal;
    }

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

}

然后你需要实现AuthSchemeFactory:

import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeFactory;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ContextAwareAuthScheme;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BufferedHeader;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;

public class BearerAuthSchemeFactory implements AuthSchemeFactory {

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

    private static class BearerAuthScheme implements ContextAwareAuthScheme {
        private boolean complete = false;

        @Override
        public void processChallenge(Header header) throws MalformedChallengeException {
            this.complete = true;
        }

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

        @Override
        public Header authenticate(Credentials credentials, HttpRequest request, HttpContext httpContext)
                throws AuthenticationException {
            CharArrayBuffer buffer = new CharArrayBuffer(32);
            buffer.append(AUTH.WWW_AUTH_RESP);
            buffer.append(": Bearer ");
            buffer.append(credentials.getUserPrincipal().getName());
            return new BufferedHeader(buffer);
        }

        @Override
        public String getSchemeName() {
            return "Bearer";
        }

        @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 this.complete;
        }
    }
}

下一步是让HttpClient接受它作为有效的方案:
    HttpContext httpContext = new BasicHttpContext();

    AuthSchemeRegistry authSchemeRegistry = new AuthSchemeRegistry();
    authSchemeRegistry.register("Bearer", new BearerAuthSchemeFactory());
    httpContext.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, authSchemeRegistry);
    AuthScope sessionScope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "Bearer");

    Credentials credentials = new TokenCredentials (token);
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(sessionScope, credentials);
    httpContext.setAttribute(ClientContext.CREDS_PROVIDER, credentialsProvider);

我通常会根据不同的上下文创建它们,并在一段时间内保留这些上下文。

更多的文档可以在这里找到。我建议避免使用“预认证”,让框架处理401挑战。

如果您想看看我在说什么,请在HTTP客户端中增加日志,这样您就可以跟踪电线对话-您将看到初始请求返回一个挑战,然后客户端将利用凭证提供程序查找适当的凭据并发送请求,以响应我们定义的方案的适当挑战响应。

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接