Java HTTPServer身份验证 - 客户端

时间:2015-01-02 23:22:44

标签: java rest http client-side basic-authentication

我实现了一个非常简单的HTTP服务器,如here所述。我设法通过使用身份验证标头来使身份验证工作,但我无法弄清楚如何从表单中获取凭据并使用它们与服务器进行身份验证。这通常是怎么做的?

代码:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.BasicAuthenticator;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class SimpleHttpServer3 {

  public static void main(String[] args) throws Exception {
    HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
    server.createContext("/info", new InfoHandler());
    HttpContext hc1 = server.createContext("/get", new GetHandler());
    hc1.setAuthenticator(new BasicAuthenticator("get") {
        @Override
        public boolean checkCredentials(String user, String pwd) {
            return user.equals("admin") && pwd.equals("password");
        }
    });
    server.setExecutor(null); // creates a default executor
    server.start();
    System.out.println("The server is running");
  }

  // http://localhost:8000/info
  static class InfoHandler implements HttpHandler {
    public void handle(HttpExchange httpExchange) throws IOException {
      String response = "Use /get to authenticate (user:admin pwd:password)";
      SimpleHttpServer3.writeResponse(httpExchange, response.toString());
    }
  }

  static class GetHandler implements HttpHandler {
    public void handle(HttpExchange httpExchange) throws IOException {
      StringBuilder response = new StringBuilder();
      response.append("<html><body>");
      response.append("hello " + httpExchange.getPrincipal().getUsername());
      response.append("</body></html>");
      SimpleHttpServer3.writeResponse(httpExchange, response.toString());
    }
  }

  public static void writeResponse(HttpExchange httpExchange, String response) throws IOException {
    httpExchange.sendResponseHeaders(200, response.length());
    OutputStream os = httpExchange.getResponseBody();
    os.write(response.getBytes());
    os.close();
  }

}

2 个答案:

答案 0 :(得分:1)

通常,大多数人会使用像Shiro或Spring Security这样的身份验证框架。

这些框架在模式上注册Servlet过滤器,例如/*,以对所有请求强制执行身份验证。它们将身份验证数据存储在Servlet会话中,以保持用户在请求之间登录,这通常由HTTP服务器通过Cookie隐式完成。他们还注册了一个特殊的上下文来接受基于表单的身份验证请求,例如对/login的POST请求。

这些基于表单的端点将读取(通常是application/x-www-form-urlencoded个请求,并提取提交的用户名和密码,以与服务器存储密码相同的方式对密码进行散列,并将它们进行比较以验证身份验证主体。< / p>

答案 1 :(得分:0)

Basic Authentication协议规定客户端请求应具有

形式的标头
Authorization: Basic Base64Encoded(username:password)

其中Base64Encoded(username:password)username:password的实际Base64编码字符串。例如,如果我的用户名和密码是peeskillet:pass,则标题应该以

的形式发送出去
Authorization: Basic cGVlc2tpbGxldDpwYXNz

the example from your link中,它使用基本身份验证。受保护资源的URL是

http://localhost:8000/get

您可以访问浏览器访问该网址,然后您会在this answer中看到一个对话框(在Firefox中)。输入admin(用户名)和password(密码)。您将收到hello admin返回消息。

您不需要自己进行任何身份验证(或至少解析/解码),因为内部(我还没有检查过源代码,但似乎是这种情况){{3解码并解析Authorization标头,并将用户名和密码传递给您实现的checkCredentials方法。由于它只允许admin/password,因此这是唯一可以进行身份​​验证的组合。

为了完整起见,解码/解析(伪代码)可能看起来像

String authHeader = request.getHeader("Authorization");
String[] split = authHeader.split("\\s");
String credentials = split[1];
String decoded = Base64.decode(credentials);
String[] userPass = decoded.split(":");

String username = userPass[0];
String password = userPass[1];

boolean authenticated = checkCredentials(username, password);

如果您想尝试使用代码发出请求,则需要在请求中设置Authorization标头。该值将是admin:password的Base64编码字符串,即YWRtaW46cGFzc3dvcmQ=。所以标题应该以

的形式发送出去
Authorization: Basic YWRtaW46cGFzc3dvcmQ=

对于其他组合,您只需BasicAuthenticator键入组合,或者Java 8具有可用于编码凭据的go here

String cred = "admin:password";
String encoded = Base64.getEncoder().encodeToString(cred.getBytes());
System.out.println(encoded);
// YWRtaW46cGFzc3dvcmQ=