手工实现HttpBasic校验
HttpBasic:
是RFC中定义的一种控制HTTP协议访问资源的方式。具体当HTTP请求受限资源时,就需要在请求头中添加以"Authorization"为key的header,value的具体形式是"Basic <credentials>", 其中<credentials>
是以“${username}:${password}"进行BASE64编码后的字符串。如果携带的这个请求头的信息和服务端保存
的用户名密码信息不匹配,就需要服务端必须返回401的状态码和WWW-Authenticate的返回头,其中值要形如
”Basic realm=testHttpBasic"其中”Basic realm"是固定死的
特性:
是最简单的控制访问方式,不需要cookies啊,session identifiers(session id)啊/login pages什么的。
各大浏览器都会以好RFC定义的约定规则实现对应的逻辑的。
实现:
SpringSecurity框架中就包含了HttpBasic的功能,但如果不想依赖这么重的玩意儿,可以自己写一个。
我是写了一个Filter,用于过滤请求,已通过Chrome浏览器验证Ok.
1 package org.zeng.test.test.web.httpbasic; 2 3 import javax.servlet.*; 4 import javax.servlet.annotation.WebFilter; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import javax.servlet.http.HttpSession; 8 import java.io.IOException; 9 import java.util.Base64; 10 11 @WebFilter(servletNames = "authFilter", urlPatterns = "/basic/*") 12 public class AuthFilter implements Filter { 13 14 private final String USERNAME = "admin"; 15 private final String PASSWORD = "123456"; 16 17 /** 18 * 核心逻辑比较简单,就是: 19 * 1.简单的字符串解析 20 * 2.解码Base64 21 * 3.验证用户名密码 22 * 4.将用户标识放入session中 23 * 24 * @param servletRequest 25 * @param servletResponse 26 * @param filterChain 27 * @throws IOException 28 * @throws ServletException 29 */ 30 @Override 31 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 32 HttpServletRequest request = (HttpServletRequest)servletRequest; 33 HttpSession session = request.getSession(); 34 35 if (session.getAttribute("user") == null) { 36 String basicValue = request.getHeader("Authorization"); 37 38 //打印出了值形如 "Basic YW423222222lalalla" 39 System.out.println("Authorization: " + basicValue); 40 41 if (basicValue != null && basicValue.length() > 0) { 42 String[] authorizationValue = basicValue.split(" "); 43 if (authorizationValue.length == 2) { 44 45 //获取到解码后的值,形如 "admin:123456" 46 String base64Encoded = new String(Base64.getDecoder().decode(authorizationValue[1])); 47 if (authorizationValue != null && base64Encoded.length() > 0) { 48 String userAndPwdArray[] = base64Encoded.split(":"); 49 if (userAndPwdArray.length != 2) { 50 checkFailed(servletResponse); 51 } else { 52 String user = userAndPwdArray[0]; 53 String password = userAndPwdArray[1]; 54 if (USERNAME.equals(user) && PASSWORD.equals(password)) { 55 56 //放入session中,下次登录无需再次提示登录框 57 session.setAttribute("user", USERNAME); 58 59 checkSuccess(servletRequest, servletResponse, filterChain); 60 } else { 61 checkFailed(servletResponse); 62 } 63 } 64 } else { 65 checkFailed(servletResponse); 66 } 67 } else { 68 checkFailed(servletResponse); 69 } 70 } else { 71 checkFailed(servletResponse); 72 } 73 } else { 74 checkSuccess(servletRequest, servletResponse, filterChain); 75 } 76 } 77 78 @Override 79 public void init(FilterConfig filterConfig) throws ServletException { 80 81 } 82 83 @Override 84 public void destroy() { 85 86 } 87 88 /** 89 * 校验成功 90 * @param servletRequest 91 * @param servletResponse 92 * @param filterChain 93 * @throws IOException 94 * @throws ServletException 95 */ 96 private void checkSuccess(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 97 filterChain.doFilter(servletRequest, servletResponse); 98 } 99 100 /** 101 * 校验失败返回 102 * @param servletResponse 103 */ 104 private void checkFailed(ServletResponse servletResponse) { 105 HttpServletResponse response = (HttpServletResponse) servletResponse; 106 response.setStatus(401); 107 response.setHeader("WWW-Authenticate", "Basic realm=anything you can write!"); 108 } 109 }