10-environment
1. ip
1. 服务端ip
public static String getHostIP() {
String sIP = "";
InetAddress ip = null;
try {
// Windows操作系统
if (isWindowsOS()) {
ip = getLocalHost();
}
// Linux操作系统
else {
boolean bFindIP = false;
Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
if (bFindIP) {
break;
}
NetworkInterface ni = netInterfaces.nextElement();
// 遍历所有ip
Enumeration<InetAddress> ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
ip = ips.nextElement();
// 开头的都是lookback地址
if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !getInetAddress(ip).contains(":")) {
// 进行ip模式匹配
if (getInetAddress(ip) != null) {
bFindIP = true;
break;
}
}
}
}
}
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("获取本机ip地址失败", e);
}
}
if (null != ip) {
sIP = getInetAddress(ip);
}
return sIP;
}
private static boolean isWindowsOS() {
boolean isWindowsOS = false;
String osName = System.getProperty("os.name");
if (osName != null && osName.toLowerCase().contains("windows")) {
isWindowsOS = true;
}
return isWindowsOS;
}
private static InetAddress getLocalHost() {
try {
return InetAddress.getLocalHost();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
private static String getInetAddress(InetAddress ip) {
return ip.getHostAddress();
}
2. 请求端ip
- Spring 获取真实Ip
- 整合网关的获取方式
- 获取客户端IP:
request.getRemoteAddr()
,这种方法大部分情况下都是有效的
在通过了Apache, Squid
等反向代理软件就不能获取到客户端的真实IP地址了,如果通过了多级反向代理的话,X-Forwarded-For
的值并不止一个,而是一串IP值, 究竟哪个才是真正的用户端的真实IP呢?
- 取
X-Forwarded-For
中第一个非unknown
的有效IP字符串 - eg:
X-Forwarded-For: 192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
。用户真实IP为:192.168.1.110
private String getRemoteIpAddr(HttpServletRequest request) {
// nginx代理获取的真实用户ip
String ip = request.getHeader("X-Real-IP");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("x-forwarded-for");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if (ip.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (Exception e) {
e.printStackTrace();
}
assert inet != null;
ip = inet.getHostAddress();
}
}
// 多个代理的情况,第一个IP为客户端真实IP,多个IP按照`,`分割
if (ip != null && ip.length() > 15) {
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
2. Cookie
1. SameSize
内嵌iframe
页面获取不到外层页面cookie
中ticket
https:
谷歌浏览器90以后只能后端来控制了samesize,https
后端来设置。http
仍然可以前端来设置
String cookieTicketKey = "";
String token = "";
if (StrUtil.isNotBlank(cookieTicketKey)) {
ResponseCookie cookie = ResponseCookie.from(cookieTicketKey, token)
.path("/")
.secure(true)
.sameSite("None")
.build();
response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
}
3. Https
1. 忽略https证书
String resEncrypt = HttpRequest.post(url)
.setSSLSocketFactory(SslSocketClient.getSslSocketFactory())
.setHostnameVerifier(SslSocketClient.getHostnameVerifier())
.body(gson.toJson(reqMap))
.timeout(8000)
.execute().body();
import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
/**
* @author: lisongtao
* @description: SslSocketClient
* @create: 2021-03-16 21:31
*/
public class SslSocketClient {
/**
* SSLSocketFactory
* 通过这个类我们可以获得SSLSocketFactory,这个东西就是用来管理证书和信任证书的
*
* @return SSLSocketFactory
*/
public static SSLSocketFactory getSslSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManager(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取TrustManager
*
* @return TrustManager[]
*/
private static TrustManager[] getTrustManager() {
// 不校检证书链
return new TrustManager[]{
new X509TrustManager() {
/**
* 不校检客户端证书
* @param chain chain
* @param authType authType
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
/**
* 不校检服务器证书
* @param chain chain
* @param authType authType
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
/**
* OKhttp3.0以前返回null,3.0以后返回new X509Certificate[]{};
* @return X509Certificate[]
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
}
/**
* 获取HostnameVerifier
*
* @return HostnameVerifier
*/
public static HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
/**
* 未真正校检服务器端证书域名
* @param s s
* @param sslSession sslSession
* @return boolean
*/
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
}
}
4. bean覆盖
- 允许bean覆盖之前相同名称的bean
allow-bean-definition-overriding
spring:
application:
name: ooxx
profiles:
active: prod
main:
allow-bean-definition-overriding: true