通辽做家教的网站,怎样在wordpress设置伪静态,网站制作手机,设计网店首页来吧#xff0c;贴代码。
一、背景
我们有一个项目使用了spring cloud#xff0c;有的微服务需要调用别的微服务#xff0c;但这些调用没有鉴权#xff1b;当初项目时间非常紧#xff0c;同时这部分微服务有的对外也没有鉴权#xff0c;在代码中设置了无须鉴权#xf…来吧贴代码。
一、背景
我们有一个项目使用了spring cloud有的微服务需要调用别的微服务但这些调用没有鉴权当初项目时间非常紧同时这部分微服务有的对外也没有鉴权在代码中设置了无须鉴权可直接访问。近期客户进行安全性测评查出了一堆安全性漏洞。你睇下
Override
public void configure(HttpSecurity http) throws Exception {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests()//添加放行接口不进行OAuth2授权认证.antMatchers(/camera/**,/jcDeviceManufacturer/file/preview/**,/jcStationFile/**,/jcTimedTask/**,/jcDevice/**,/jcStation/**,/user/query/warning/**,/jcSenorDataCurrent/**,/jcSensorData003/**,/jcSensorData007/**,/jcSensorData008/**,/jcSensorData009/**,/jcSensorData012/**,/jcSensorData014/**,/jcSensorData015/**,/jcSensorData024/**,/jcSensorData025/**,/jcSensorData027/**,/jcSensorData034/**,/jcSensorGnssResolvedata/**,/jcSensorDataDxs/**,/jcSensorDataGnss/**,/jcStationMap/**,/jcWarnConfigDevice/**,/jcStationDeviceMap/**).permitAll()// 指定监控访问权限.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll().anyRequest().authenticated().and()//认证鉴权错误处理.exceptionHandling().accessDeniedHandler(new OpenAccessDeniedHandler()).authenticationEntryPoint(new OpenAuthenticationEntryPoint()).and().csrf().disable();
}如之奈何计将安出
二、思路
项目早就验收了维护期也过期了。本着为客户着想并幻想他们能再续期丢个几万元让我们维护所以我奋不顾身地维护一下。
我的指导原则是代码不要进行大的调整尽量简单处理毕竟量体裁衣看菜吃饭。而且当时项目开发的人很多我只负责其中几个模块好多都不是我弄的。现在人员已经走得差不多了维护任务就落到我头上。我只好硬着猪头皮献上思路如下 1微服务间调用检查请求头有无带上特定信息有则通过无则抛出异常 2外部访问设置白名单检查发出请求的IP符合则通过否则抛出异常。这样第三方系统就不用更改了 3但这些服务中有一些前端也会请求。由于前端有登录那么前端的请求应该不受上面的限制措施影响。 4搞一个标注来完成这些鉴权动作并且应用AOP尽量将现有代码改动减到最小。 三、具体实现
1、标注Inner用于标记类
import java.lang.annotation.*;/*** 微服务内部访问方法*/
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Documented
public interface Inner {/*** 是否AOP统一处理*/boolean value() default true;
}2、标注InnerMethod用于标记方法
import java.lang.annotation.*;/*** 微服务内部访问方法*/
Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
Documented
public interface InnerMethod {/*** 是否AOP统一处理*/boolean value() default true;
}3、AOP
1InnerAspect.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;Aspect
Component
public class InnerAspect implements Ordered {
/**
配置文件内容
inner.head.nameX-From
inner.head.valueinternal
inner.white-ip127.0.0.1,192.168.10.8,192.168.10.9
*/Value(value ${inner.head.name:X-From})private String from;Value(value ${inner.head.value:internal})private String fromIn;Value(value ${inner.white-ip:127.0.0.1})private String whiteIps;private static ListString whiteList null;Around(within(inner)) // Modified pointcut expressionpublic Object around(ProceedingJoinPoint point, Inner inner) throws Throwable {if(!isValid(point,inner.value())){throw new AccessDeniedException(Access is denied);}return point.proceed(); // Proceed with the original method call}/*** 注意 Around(annotation(innerMethod))中的innerMethod,* 名称要与aroundMethod(ProceedingJoinPoint point, InnerMethod innerMethod) 中的参数名称一致* param point* param innerMethod* return* throws Throwable*/Around(annotation(innerMethod))public Object aroundMethod(ProceedingJoinPoint point, InnerMethod innerMethod) throws Throwable {if(!isValid(point,innerMethod.value())){throw new AccessDeniedException(Access is denied);}return point.proceed();}Overridepublic int getOrder() {return Ordered.HIGHEST_PRECEDENCE 1;}private boolean isValid(ProceedingJoinPoint point, boolean innerHasValue){boolean yes true;Authentication authentication SecurityContextHolder.getContext().getAuthentication();if (authentication null || anonymousUser.equals(authentication.getPrincipal())){//尚未登录initWhiteList();Signature signature point.getSignature();if (innerHasValue) { // Check if AOP is enabled for the classHttpServletRequest request ServletUtils.getRequest();String header request.getHeader(from);String ipAddress getOriginalIp(request);// Authorization check based on request header or IP addressif (!fromIn.equals(header) !whiteList.contains(ipAddress)) {System.err.println(String.format(没有权限访问接口 %s, signature.getName()));yes false;}}}return yes;}private void initWhiteList(){if(whiteList null || whiteList.size() 0){whiteList new ArrayList(Arrays.asList(whiteIps.split(,)));}}/*** 获取最原始的请求IP* 因为请求有可能经过nginx等转发* param request* return*/private String getOriginalIp(HttpServletRequest request) {String originalIp request.getHeader(X-Forwarded-For);if (originalIp null || originalIp.isEmpty()) {originalIp request.getRemoteAddr();} else {// 可能会有多个IP获取第一个IP地址originalIp originalIp.split(,)[0].trim();}return originalIp;}
}
其中主要逻辑部分
private boolean isValid(ProceedingJoinPoint point, boolean innerHasValue){boolean yes true;Authentication authentication SecurityContextHolder.getContext().getAuthentication();if (authentication null || anonymousUser.equals(authentication.getPrincipal())){//尚未登录initWhiteList();Signature signature point.getSignature();if (innerHasValue) { // Check if AOP is enabled for the classHttpServletRequest request ServletUtils.getRequest();String header request.getHeader(from);String ipAddress getOriginalIp(request);// Authorization check based on request header or IP addressif (!fromIn.equals(header) !whiteList.contains(ipAddress)) {System.err.println(String.format(没有权限访问接口 %s, signature.getName()));yes false;}}}return yes;
}首先看是否已经登录未登录的话才进行考察。如果既无请求头又不在白名单内才抛出异常否则都通过宽松得很。
值得一提得是Around的写法。里面的参数要跟函数的参数保持一致
2自定义的HttpServletRequest.java
上面代码中用到这个自定义类。
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;public class ServletUtils {public static HttpServletRequest getRequest() {return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();}
}四、使用
1、被调用的服务
1类
Api(value 监测设备信息, tags 监测设备信息)
RestController
RequestMapping(jcDevice)
Inner
public class JcDeviceController implements IJcDeviceServiceClient {
。。。
}2方法 GetMapping(/file/preview)InnerMethodpublic void previewDemo(HttpServletRequest request, HttpServletResponse response, RequestParam(code) String code) {
。。。}2、主动发起调用的服务
服务之间是通过Feign来调用的只要在主动发起调用的微服务中实现Feign的拦截器即可
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;Component
public class InnerAuthInterceptor implements RequestInterceptor {Value(value ${inner.head.name:X-From})private String from;Value(value ${inner.head.value:internal})private String fromIn;Overridepublic void apply(RequestTemplate template) {template.header(from, fromIn);}
}五、小结
上述代码中IP白名单在本地是没有问题的。但请求的转发是vue开发环境下实现的。部署到生产服务器nginx上就拿不到最原始的请求IP拿到的都是nginx服务器的IP。这个问题下周有时间再看看。
但不一定有时间。公司没啥活员工却还是那么忙搞不懂。
参考文章 服务之间调用还需要鉴权
Feign的拦截器RequestInterceptor