需求:只允许内网的IP(也就是IP白名单)进行访问VideoController和ImgController,其余的FontController可以随便访问不做限制
总体的项目结构:
访问的路径分别是:
/api/video/video1
/api/img/img1
/api/font/font1
package com.cao.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/font")
public class FontController {
@RequestMapping("/font1")
public String getFont(){
return "This is a font!";
}
}
package com.cao.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/img")
public class ImgController {
@RequestMapping("/img1")
public String getImg(){
return "This is a img!";
}
}
package com.cao.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/video")
public class VideoController {
@RequestMapping("/video1")
public String getVideo(){
return "This is a video!";
}
}
在yml文件中进行配置要放行的IP白名单,是一个List
server:
port: 8888
myapp:
allowedIps:
- 127.0.0.3
- 127.0.0.2
用于接收yml中配置的IP白名单,注意配置和属性之间的名称要一致:myapp.allowedIps
package com.cao.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 该类用于接收yml中配置的IP白名单
*/
@Data
@Component
@ConfigurationProperties(prefix = "myapp")
public class WhiteIpProperties {
private List<String> allowedIps;
}
这里的需求是打印出来访问VideoController和ImgController的非白名单的IP并设置返回状态为 403
package com.cao.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 定义拦截器以及执行时候的业务代码
*/
@Slf4j
public class IpAddressInterceptor implements HandlerInterceptor {
private List<String> allowedIps;
public IpAddressInterceptor(List<String> allowedIps) {
this.allowedIps = allowedIps;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ipAddress = request.getRemoteAddr();
if (allowedIps.contains(ipAddress)) {
return true;
} else {
log.info("该ip不在访问的白名单中:{}", ipAddress);
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return false;
}
}
}
注册拦截器的时候进行配置访问路径,在WebMvcConfig中addPathPatterns中加上要限制的url
package com.cao.config;
import com.cao.interceptor.IpAddressInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* 用于注册拦截器
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private WhiteIpProperties whiteIpProperties;
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> allowedIps = whiteIpProperties.getAllowedIps();
registry.addInterceptor(new IpAddressInterceptor(allowedIps))
.addPathPatterns("/api/video/**", "/api/img/**")
.excludePathPatterns("/error");
}
}
我们现在配置的白名单是:127.0.0.2、127.0.0.3,所以用127.0.0.1是访问不到VideoController和ImgController中对应的url,但是可以访问到FontController中的url
访问VideoController和ImgController,返回的状态是403,看到打印的日志
将127.0.0.1加入到白名单中,再次测试,三个Controller都应该能够访问到
进行访问:
OK 测试没有问题。
package com.cao.advice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Component
@RestControllerAdvice
@Slf4j
public class EncryptionResponseBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true; //对所有请求进行处理
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType,
Class selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
ServletServerHttpRequest httpRequest = (ServletServerHttpRequest) request;
log.info("调用uri:{}", httpRequest.getServletRequest().getRequestURI());
String bodyString = (String) body;
log.info("没有加密的string:{}", bodyString);
//对返回结果进行加密
String encryptedBody = encryptBody(body);
log.info("加密后的encryptedBody:{}", encryptedBody);
return encryptedBody;
}
private String encryptBody(Object body) {
String string = body.toString();
byte[] encryptedBytes = Base64.getEncoder().encode(string.getBytes(StandardCharsets.UTF_8));
return new String(encryptedBytes, StandardCharsets.UTF_8);
}
}