Basic认证

497 阅读2分钟

背景

今天看到swagger-ui的basic认证,只需一次登录就长期有效,关闭浏览器才能注销,这是他的特点

原理

  1. 浏览器初次访问,得到401 Authorization Required,返回 WWW-Authenticate 首部字段(响应头)的响应。该字段内包含认证的方式(BASIC)及Request-URI 安全域字符串(realm)
  2. 接收到状态码 401 的客户端为了通过 BASIC 认证,需要将用户ID及密码发送给服务器。发送的字符串内容是由用户名 ID 和密码构成,两者中间以冒号(:)连接后,再经过 Base64 编码处理。
  3. 接收到包含首部字段 Authorization 请求的服务器,会对认证信息的正确性进行验证。如果验证通过,则返回一条包含 Request-URI 资源的响应

验证

  1. 收到401,Basic realm 1649690888(1).png

  2. 输入账号密码后,请求header带上了Authorization: Baisc xxxxx(Base64编码)

image.png

Java简单实现Basic认证

@Controller
public class IndexController {

    private static final Base64.Decoder decoder = Base64.getDecoder();
    // private static final Base64.Encoder encoder = Base64.getEncoder();

    @RequestMapping("/login")
    @ResponseBody
    public String login(HttpServletRequest req, HttpServletResponse res) {
        if (!isAuth(req, res)) {
            return "{code: 401, msg: \"no auth\"}";
        }
        return "{code: 0, data: {username:\"test\"}}";
    }
    
    @RequestMapping("/index")
    @ResponseBody
    public String index(HttpServletRequest req, HttpServletResponse res) {
        if (!isAuth(req, res)) {
            return "{code: 401, msg: \"no auth\"}";
        }
        return "{code: 0, data: {xxx:\"xxx\"}}";
    }

    private boolean isAuth(HttpServletRequest req, HttpServletResponse res) {
        String base6AuthStr = req.getHeader("Authorization");
        System.out.println("base6AuthStr=" + base6AuthStr); // base6AuthStr=Basic YWFhOmFhYQ==
        if (base6AuthStr == null) {
            res.setStatus(401);
            res.addHeader("WWW-Authenticate", "basic realm=\"no auth\"");
            return false;
        }

        String authStr = new String(decoder.decode(base6AuthStr.substring(6).getBytes()));
        System.out.println("authStr=" + authStr); // authStr=xxx:xxx

        String[] arr = authStr.split(":");
        if (arr != null && arr.length == 2) {
            String username = arr[0];
            String password = arr[1];
            // 校验用户名和密码
            if ("test".equals(username) && "123456".equals(password)) {
                return true;
            }
        }
        // 用户名 ID 和密码校验失败后,重新返回 401 和 WWW-Authenticate 响应头,从而可以重复质询
        res.setStatus(401);
        res.addHeader("WWW-Authenticate", "basic realm=\"no auth\"");
        return false;
    }
}

缺点

  1. BASIC 认证虽然采用 Base64 密码方式,但这不是加密处理。不需要任何附加信息即可对其进行解码。换言之,由于明文解码后就是用户名 ID 和密码,再 HTTP 等非加密通信线路上进行 BASIC 认证的过程中,如果被人窃听,被盗的可能性极高。所以,BASIC 认证需要配合HTTPS来保证信息传输的安全。
  2. 即使密码被强加密,第三方仍可通过加密后的用户名和密码进行重放攻击
  3. 如果想再进行一次 BASIC 认证时,一般的浏览器却无法实现认证注销操作。所以,BASIC 认证使用上不够灵活,且达不到多数 Web 网站期望的安全性等级,因此并不常用。

参考: www.cnblogs.com/xy-ouyang/p…