Java Web 实现 HTTP Basic 4年前

编程语言
469
Java Web 实现 HTTP Basic

Basic 认证是一种较为简单的 HTTP 认证方式,客户端通过明文(Base64 编码格式)传输用户名和密码到服务端进行认证,通常需要配合 HTTPS 来保证信息传输的安全。界面如下。

下面基于 Servlet 标准 Filter 实现一个 HTTP Basic 登录机制,可以用作测试时的临时发布用。部分函数利用了 AJAXJS 库。

package com.ajaxjs.web;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ajaxjs.util.Encode;
import com.ajaxjs.util.CommonUtil;
import com.ajaxjs.util.logger.LogHelper;

/**
 * 简单的 HTTP Basic 登录
 * 
 * @author sp42 frank@ajaxjs.com
 */
public class HttpBasicAuthFilter implements Filter {
    private static final LogHelper LOGGER = LogHelper.getLog(HttpBasicAuthFilter.class);

    /**
     * 登录名,写死只有一个用户 admin
     */
    private static final String userid = "admin";

    /**
     * 登录密码
     */
    private static String pwd = "123123";
    
    /**
     * 报告是否启动的状态,让外界知晓
     */
    public static boolean isEnadble = false;

    @Override
    public void init(FilterConfig config) throws ServletException {
        LOGGER.info("启动 HTTP BasicAuth 后台管理");

        if (config.getInitParameter("adminPassword") != null)
            pwd = config.getInitParameter("adminPassword");// 读取 web.xml 配置里的密码
        
        isEnadble = true;
    }

    @Override
    @SuppressWarnings("deprecation")
    public void doFilter(ServletRequest _request, ServletResponse _response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) _request;
        HttpServletResponse response = (HttpServletResponse) _response;

        if (!checkAuth(request)) {
            String msg = "\"Please input your account\""; // 如果认证失败,则要求认证 ,不能输入中文

            response.setCharacterEncoding("utf-8");
            response.setStatus(401, "Authentication Required");// 发送状态码 401, 不能使用 sendError,坑
            response.setHeader("WWW-Authenticate", "Basic realm=" + msg);// 发送要求输入认证信息,则浏览器会弹出输入框
            response.setCharacterEncoding("utf-8");
            response.getWriter().append("<meta charset=\"utf-8\" />Please login! 请登录系统!");

            LOGGER.info("HTTP BasicAuth 登录失败!");
        } else {
            // request.setAttribute("userName", userid);
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
    }

    /**
     * 检查是否合法登录
     * 
     * @param request 请求对象
     * @return 是否合法登录
     */
    private static boolean checkAuth(HttpServletRequest request) {
        return checkAuth(request.getHeader("Authorization"), userid, pwd);
    }

    /**
     * 是否不合法的数组
     * 
     * @param arr
     * @return 是否不合法的数组
     */
    private static boolean isBadArray(String[] arr) {
        return arr == null || arr.length != 2;
    }

    /**
     * 检查是否合法登录
     * 
     * @param authorization 认证后每次HTTP请求都会附带上 Authorization 头信息
     * @param username 用户名
     * @param password 密码
     * @return true = 认证成功/ false = 需要认证
     */
    private static boolean checkAuth(String authorization, String username, String password) {
        if (CommonUtil.isEmptyString(authorization))
            return false;

        String[] basicArray = authorization.split("\\s+");
        if (isBadArray(basicArray))
            return false;

        String idpass = Encode.base64Decode(basicArray[1]);
        if (CommonUtil.isEmptyString(idpass))
            return false;

        String[] idpassArray = idpass.split(":");
        if (isBadArray(idpassArray))
            return false;

        return username.equalsIgnoreCase(idpassArray[0]) && password.equalsIgnoreCase(idpassArray[1]);
    }
}

HTTP Basic 安全性还是太弱,所以可以考虑加强版: 摘要认证——HTTP Digest。

image
magicwaltz
我已经准备好了足够挡雨的伞,可是却迟迟没有等到雨的到来,这样的尴尬只是我漫长人生中的小插曲罢了。
6
发布数
2
关注者
14597
累计阅读

热门教程文档

HTML
32小节
CSS
33小节
10.x
88小节
Swift
54小节
Typescript
31小节
广告