一、web.xml:
<filter> <filter-name>fastLoginFilter</filter-name> <filter-class>com.xxx.xf.common.util.FastLoginFilter</filter-class> </filter> <filter-mapping> <filter-name>fastLoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
配置文件中配置一下訪問路徑可以用作過濾時候判斷,可以直接放行和加密不加密操作:
passUrls=.html;.css;.js;/main/img/;/main/common/;/mlsc-upload/service/sys/file/upload;\
其中,訪問靜態資源肯定是直接放行不過濾不加密的;
二、java代碼:
package com.xxx /** * 用於快速登錄的過濾器,僅放行passUrlList中的路徑 */ public class FastLoginFilter implements Filter { public static final String TICKET_ID = "ticketId"; public static Logger logger = LoggerUtil.getLoggerByName("system", "loginFilter"); public static String HOME_URL = "/index.html"; public static String LOGIN_URL = "/login.html"; public static String INVALID_URL = "/login.html"; /** * 用於攔截快速登錄的請求 */ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String requestURL = request.getRequestURI(); String retUrl = request.getHeader("Referer"); // 保留未登錄websocket通信 if(requestURL.indexOf("/websocket/") == -1){ if(retUrl==null&&!requestURL.equals(LOGIN_URL)||retUrl!=null&&!checkWebReferer(retUrl)){ response.sendRedirect(LOGIN_URL); return; } } if (checkIsPassUrl(requestURL)) { chain.doFilter(req, resp); return; } Object ticketId = request.getSession().getAttribute(TICKET_ID); // Object ticketId = request.getParameter(TICKET_ID); String requestType = request.getHeader("x-requested-with"); String userAgent = request.getHeader("user-agent"); if (ticketId == null) { if ((requestType != null && requestType.equals("XMLHttpRequest")) || checkApp(userAgent)) { writeUnloginInfo((HttpServletResponse) response); } else { response.sendRedirect(LOGIN_URL); } return; } boolean isLogged = this.isLogged(ticketId.toString()); String checkLoginStatus = request.getParameter("checkLoginStatus"); if (StringUtils.isNotNullOrEmpty(checkLoginStatus)) { resp.getWriter().write(String.valueOf(isLogged)); return; } UserInfo userInfo = CacheUtil.getUserByTicket(ticketId.toString(), UserInfo.class); if (userInfo != null && StringUtils.isNotNullOrEmpty(userInfo.getUserId())) { CacheUtil.refreshTicket(ticketId.toString(), userInfo.getUserId()); String token = request.getHeader("token"); String contentType=request.getContentType(); if("1".equals(ConfigUtil.get("aesOpen"))&&"XMLHttpRequest".equals(requestType)&&StringUtils.isNotNullOrEmpty(token) &&"encryption".equals(token)){ //和前台一樣的判斷是否需要加解密操作 String requestBodyMw = null; String rsaResult=null; try { String p=""; if("application/json".equals(contentType)){ String requestBody = getRequestParam((HttpServletRequest) request); logger.info(requestBody); JSONObject jsonObject=JSONObject.parseObject(requestBody); p=jsonObject.getString("p"); //獲取前台傳的加密之后的參數p }else{ p=request.getParameter("p"); } requestBodyMw = CryptionUtil.aesDecrypt(p.trim(), ConfigUtil.get("aecKey")); //先將請求參數進行aes解密 rsaResult= RSAEncryptUtils.decrypt(requestBodyMw); //再將前台傳的參數進行RSA解密,步驟與前台相反 } catch (Exception e) { writeUnloginInfo((HttpServletResponse) response); return; } WrapperedResponse wrapResponse = new WrapperedResponse((HttpServletResponse) response); //封裝的響應對象 WrapperedRequest wrapRequest = new WrapperedRequest((HttpServletRequest) request, rsaResult); //封裝的請求對象 chain.doFilter(wrapRequest, wrapResponse); //調用自己框架的過濾器方法,獲取當前用戶之類的 byte[] data = wrapResponse.getResponseData(); String resData=new String(data, "utf-8"); JSONObject resultObj=new JSONObject(); try { resultObj.put("data",CryptionUtil.aesEncrypt(resData, ConfigUtil.get("aecKey"))); //返回的參數也是aes加密的 } catch (Exception e) { e.printStackTrace(); } writeResponse(response, resultObj.toJSONString()); return; } } else { if ((requestType != null && requestType.equals("XMLHttpRequest")) || checkApp(userAgent)) { writeUnloginInfo((HttpServletResponse) response); } else { response.sendRedirect(INVALID_URL); } return; } chain.doFilter(req, resp); return; } private boolean checkWebReferer(String retUrl){ boolean flag=false; String configWebReferer=ConfigUtil.get("webReferer"); String[] webRefererArr=configWebReferer.split(","); for(int i=0;i<webRefererArr.length;i++){ if(retUrl.startsWith(webRefererArr[i])){ flag=true; break; } } return flag; } private void writeResponse(ServletResponse response, String responseString) throws IOException { PrintWriter out = response.getWriter(); response.setContentLength(responseString.length()); out.print(responseString); out.flush(); out.close(); } private String getRequestParam(HttpServletRequest request){ ServletInputStream inputStream = null; StringBuilder sb = new StringBuilder(); try { inputStream = request.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } // 獲取請求路徑,如果是:/fastLoginWS,則直接放行 public boolean checkIsPassUrl(String requestURL) throws IOException, ServletException { boolean isPass = false; if (StringUtils.isNotNullOrEmpty(requestURL)) { // 判斷訪問的路徑是否為路徑放行集合中的路徑,如果含有,則直接放行 for (String url : ConfigUtil.PASS_URLS) { //配置文件中可以配置一下訪問路徑,用於不用過濾,不用進行加解密操作等 if (requestURL.indexOf(url) != -1) { isPass = true; break; } } } return isPass; } private boolean checkApp(String userAgent) { if (userAgent != null) { if (userAgent.indexOf("okhttp") != -1) { return true; } if (userAgent.indexOf("Darwin") != -1) { return true; } if(userAgent.indexOf("MicroMessenger")>-1){ return true; } } return false; } private void writeUnloginInfo(HttpServletResponse response) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); //設置狀態碼 response.setContentType(MediaType.APPLICATION_JSON_VALUE); //設置ContentType response.setCharacterEncoding("UTF-8"); //避免亂碼 response.setHeader("Cache-Control", "no-cache, must-revalidate"); try { response.getWriter().write("{\"statusCode\":1001,\"loginUrl\":\"" + LOGIN_URL + "\",\"success\":false,\"msg\":\"用戶身份已經失效! \"}"); } catch (IOException e) { logger.error("與客戶端通訊異常:" + e.getMessage(), e); } } public static boolean isLogged(String ticketId) { if (ticketId == null) { return false; } else { return CacheUtil.isExist(CacheUtil.PREFIX_TICKET_USER.concat(ticketId)); } } public void init(FilterConfig arg0) throws ServletException { String homeUrl = ConfigUtil.get("homeUrl"); if (StringUtils.isNotNullOrEmpty(homeUrl)) { HOME_URL = homeUrl; } String loginUrl = ConfigUtil.get("loginUrl"); if (StringUtils.isNotNullOrEmpty(loginUrl)) { LOGIN_URL = loginUrl; } String invalidUrl = ConfigUtil.get("invalidUrl"); if (StringUtils.isNotNullOrEmpty(invalidUrl)) { INVALID_URL = invalidUrl; } } public void destroy() { } }
封裝請求對象WrapperedRequest:
package com.xxx import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; public class WrapperedRequest extends HttpServletRequestWrapper { private String requestBody = null; HttpServletRequest req = null; public WrapperedRequest(HttpServletRequest request) { super(request); this.req = request; } public WrapperedRequest(HttpServletRequest request, String requestBody) { super(request); this.requestBody = requestBody; this.req = request; } /* * (non-Javadoc) * * @see javax.servlet.ServletRequestWrapper#getReader() */ @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new StringReader(requestBody)); } /* * (non-Javadoc) * * @see javax.servlet.ServletRequestWrapper#getInputStream() */ @Override public ServletInputStream getInputStream() throws IOException { return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } private InputStream in = new ByteArrayInputStream( requestBody.getBytes(req.getCharacterEncoding())); @Override public int read() throws IOException { return in.read(); } }; } }
封裝響應對象WrapperedResponse:
package com.xxx import javax.servlet.ServletOutputStream; import javax.servlet.WriteListener; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.*; public class WrapperedResponse extends HttpServletResponseWrapper { private ByteArrayOutputStream buffer = null; private ServletOutputStream out = null; private PrintWriter writer = null; public WrapperedResponse(HttpServletResponse resp) throws IOException { super(resp); buffer = new ByteArrayOutputStream();// 真正存儲數據的流 out = new WapperedOutputStream(buffer); writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding())); } /** 重載父類獲取outputstream的方法 */ @Override public ServletOutputStream getOutputStream() throws IOException { return out; } /** 重載父類獲取writer的方法 */ @Override public PrintWriter getWriter() throws UnsupportedEncodingException { return writer; } /** 重載父類獲取flushBuffer的方法 */ @Override public void flushBuffer() throws IOException { if (out != null) { out.flush(); } if (writer != null) { writer.flush(); } } @Override public void reset() { buffer.reset(); } /** 將out、writer中的數據強制輸出到WapperedResponse的buffer里面,否則取不到數據 */ public byte[] getResponseData() throws IOException { flushBuffer(); return buffer.toByteArray(); } /** 內部類,對ServletOutputStream進行包裝 */ private class WapperedOutputStream extends ServletOutputStream { private ByteArrayOutputStream bos = null; public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException { bos = stream; } @Override public void write(int b) throws IOException { bos.write(b); } @Override public void write(byte[] b) throws IOException { bos.write(b, 0, b.length); } @Override public boolean isReady() { return false; } @Override public void setWriteListener(WriteListener writeListener) { } } }
aes加解密的java封裝類:
package com.xxx import java.math.BigInteger; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import sun.misc.BASE64Decoder; /** * AES的加密和解密 * @author libo */ public class CryptionUtil { //密鑰 (需要前端和后端保持一致) // private static String KEY = ConfigUtil.get("aecKey"); //算法 private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; /** * aes解密 * @param encrypt 內容 * @return * @throws Exception */ public static String aesDecrypt(String encrypt) { try { return aesDecrypt(encrypt, ConfigUtil.get("aecKey")); } catch (Exception e) { e.printStackTrace(); return ""; } } /** * aes加密 * @param content * @return * @throws Exception */ public static String aesEncrypt(String content) { try { return aesEncrypt(content, ConfigUtil.get("aecKey")); } catch (Exception e) { e.printStackTrace(); return ""; } } /** * 將byte[]轉為各種進制的字符串 * @param bytes byte[] * @param radix 可以轉換進制的范圍,從Character.MIN_RADIX到Character.MAX_RADIX,超出范圍后變為10進制 * @return 轉換后的字符串 */ public static String binary(byte[] bytes, int radix){ return new BigInteger(1, bytes).toString(radix);// 這里的1代表正數 } /** * base 64 encode * @param bytes 待編碼的byte[] * @return 編碼后的base 64 code */ public static String base64Encode(byte[] bytes){ return Base64.encodeBase64String(bytes); } /** * base 64 decode * @param base64Code 待解碼的base 64 code * @return 解碼后的byte[] * @throws Exception */ public static byte[] base64Decode(String base64Code) throws Exception{ return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code); } /** * AES加密 * @param content 待加密的內容 * @param encryptKey 加密密鑰 * @return 加密后的byte[] * @throws Exception */ public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); Cipher cipher = Cipher.getInstance(ALGORITHMSTR); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES")); return cipher.doFinal(content.getBytes("utf-8")); } /** * AES加密為base 64 code * @param content 待加密的內容 * @param encryptKey 加密密鑰 * @return 加密后的base 64 code * @throws Exception */ public static String aesEncrypt(String content, String encryptKey) throws Exception { return base64Encode(aesEncryptToBytes(content, encryptKey)); } /** * AES解密 * @param encryptBytes 待解密的byte[] * @param decryptKey 解密密鑰 * @return 解密后的String * @throws Exception */ public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); Cipher cipher = Cipher.getInstance(ALGORITHMSTR); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES")); byte[] decryptBytes = cipher.doFinal(encryptBytes); return new String(decryptBytes); } /** * 將base 64 code AES解密 * @param encryptStr 待解密的base 64 code * @param decryptKey 解密密鑰 * @return 解密后的string * @throws Exception */ public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception { return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey); } /** * 測試 */ public static void main(String[] args) throws Exception { String content = "123"; System.out.println("加密前:" + content); System.out.println("加密密鑰和解密密鑰:" + ConfigUtil.get("aecKey")); String encrypt = aesEncrypt(content, ConfigUtil.get("aecKey")); System.out.println("加密后:" + encrypt); String decrypt = aesDecrypt(encrypt, ConfigUtil.get("aecKey")); System.out.println("解密后:" + decrypt); } }
RSA加解密的java封裝類:
package com.xxx import org.apache.commons.lang3.StringUtils; import javax.crypto.Cipher; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.util.ArrayList; /** * RSA幫助類 * * @author liww * */ public class RSAEncryptUtils { /** * 模 */ private static String module = "ybhndrU9d3UJzvD8WSS1chQ2ZLcn7Y/ZF0SZFJbdWxkvZYAcICUzfJBF4SecxG+ia9GseNDoQ30q+mSM5Ae1NaAy2bjmR1esS17AyX/TnSvtZIm0ACIVLIM6ShM+ukMj/TEhugarwHXhiHmEd8ZkMrVu4SW2XPgWjX7yPoEKLFs="; /** * 公鑰指數 */ private static String exponentString = "AQAB"; private static String delement = "NXVBNhxh5b6GkukadyVbUJg6sgY39qUgiyIKz4ILt5C9FtEUoxA4zNIPMtQkn4pWKOywIHR8mSYatbDgBa5lPxBemwvu5cMHVIh0sD25AL+jXk29alVOIPVTpZ/0TDgy7jd7psYUIX7EO80TnvJIOaNcGUNo060H9qpo19x2iYE="; /** * 生成加密后的字節數組 * * @param value * 待加密字符串 * @param keyXmlString * 加密字符串 * @return */ public static ArrayList<byte[]> encryptToByteArrayList(String value, String keyXmlString) { try { byte[] modulusBytes = org.apache.commons.codec.binary.Base64.decodeBase64(module); byte[] exponentBytes = org.apache.commons.codec.binary.Base64.decodeBase64(exponentString); BigInteger modulus = new BigInteger(1, modulusBytes); BigInteger exponent = new BigInteger(1, exponentBytes); RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent); KeyFactory fact = KeyFactory.getInstance("RSA"); PublicKey pubKey = fact.generatePublic(rsaPubKey); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); int splitLength = 39; ArrayList<byte[]> byteArrayList = new ArrayList<byte[]>(); int i = 0; do { int Length = ((i + 1) * splitLength) >= value.length() ? (value.length() - i * splitLength) : splitLength; byte[] byteArray = cipher.doFinal(value.substring(i * splitLength, Length).getBytes("UTF-8")); byteArrayList.add(byteArray); i++; } while (i * splitLength < value.length()); return byteArrayList; } catch (Exception e) { e.printStackTrace(); } return null; } /** * RSA加密字符串 * * @param value * 需要加密的字符串 * @param keyXmlString * 加密key字符串 * @return */ public static String encrypt(String value, String keyXmlString) { ArrayList<byte[]> byteArrayList = encryptToByteArrayList(value, keyXmlString); StringBuilder sb = new StringBuilder(); for (byte[] byteArray : byteArrayList) { sb.append(bytesToHexString(byteArray)); sb.append(","); } if (sb.length() != 0) { sb.delete(sb.length() - 1, sb.length()); } return sb.toString(); } /** * RSA加密字符串 * * @param value * 需要加密的字符串 * @return */ public static String encrypt(String value) { return encrypt(value, null); } public static byte[] Dencrypt(byte[] encrypted) { try { byte[] expBytes = org.apache.commons.codec.binary.Base64.decodeBase64(delement); byte[] modBytes = org.apache.commons.codec.binary.Base64.decodeBase64(module); BigInteger modules = new BigInteger(1, modBytes); BigInteger exponent = new BigInteger(1, expBytes); KeyFactory factory = KeyFactory.getInstance("RSA"); Cipher cipher = Cipher.getInstance("RSA"); RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modules, exponent); PrivateKey privKey = factory.generatePrivate(privSpec); cipher.init(Cipher.DECRYPT_MODE, privKey); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } catch (Exception e) { e.printStackTrace(); } return null; } /** * RSA解密字節流 * * @param byteArrayList * 需要解密字節流泛型 * @param keyXmlString * 加密key字符串 * @return * @throws UnsupportedEncodingException */ public static String decrypt(ArrayList<byte[]> byteArrayList, String keyXmlString) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); for (byte[] byteArray : byteArrayList) { sb.append(new String(Dencrypt(byteArray), "UTF-8")); } return sb.toString(); } /** * RSA解密字符串 * * @param value * 需要解密的字符串 * @param keyXmlString * 加密key字符串 * @return * @throws UnsupportedEncodingException */ public static String decrypt(String value, String keyXmlString) throws UnsupportedEncodingException { ArrayList<byte[]> byteArrayList = new ArrayList<byte[]>(); if (StringUtils.isNotBlank(value)) { String[] strArray = value.split(","); int byteArrayLength = 0; byte[] byteArray; for (String str : strArray) { byteArrayLength = str.length() / 2; byteArray = new byte[byteArrayLength]; for (int i = 0; i < byteArrayLength; i++) { try { byteArray[i] = Integer.valueOf(str.substring(i * 2, (i + 1) * 2), 16).byteValue(); } catch (NumberFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } } byteArrayList.add(byteArray); } } return decrypt(byteArrayList, keyXmlString); } /** * RSA解密字符串 * * @param value * 需要解密的字符串 * @return */ public static String decrypt(String value) { try { return decrypt(value, null); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } /** * 將字節數組轉換為16進制字符串. 可以將byte轉換成int,然后利用Integer.toHexString(int)來轉換成16進制字符串。 * * @param src * 字節數組 * @return hex string */ public static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } /** * 將16進制字符串轉換為數組 * * @param hexString * 16進制字符串 * @return byte[] */ public static byte[] hexStringToBytes(String hexString) { if (hexString == null || hexString.equals("")) { return null; } hexString = hexString.toUpperCase(); int length = hexString.length() / 2; char[] hexChars = hexString.toCharArray(); byte[] d = new byte[length]; for (int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } /** * 將字符轉換為字節 * * @param c * 待轉換的字符 * @return byte 轉換后的字節 */ private static byte charToByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } }