Commit 50509e46 by xmh

gateway:

添加 authorization 校验和过滤
1 parent b1d7f0a5
...@@ -23,9 +23,10 @@ public class VionConfig { ...@@ -23,9 +23,10 @@ public class VionConfig {
private Image image; private Image image;
private boolean enableForward; private boolean enableForward;
private boolean enableAuthorization; private String authPath;
private Gateway gateway; private Gateway gateway;
private List<String> supportedVideoFormats; private List<String> supportedVideoFormats;
private List<String> skipAuth;
public @Getter public @Getter
......
package com.viontech.fanxing.forward;
import com.alibaba.fastjson.JSONObject;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import java.util.Map;
/**
* .
*
* @author 谢明辉
* @date 2021/9/29
*/
@FeignClient(name = "auth", url = "${vion.auth-path}")
public interface AuthClient {
@PostMapping(value = "/api/v1/auth/authorize", produces = MediaType.APPLICATION_JSON_VALUE)
JSONObject checkToken(@RequestHeader("authorization") String token, @RequestBody Map<String, Object> data);
}
package com.viontech.fanxing.forward; package com.viontech.fanxing.forward;
import com.alibaba.fastjson.JSONObject;
import com.viontech.fanxing.commons.config.VionConfig; import com.viontech.fanxing.commons.config.VionConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.context.config.annotation.RefreshScope; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus; import org.springframework.http.*;
import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* . * .
...@@ -28,18 +36,51 @@ public class AuthorizationFilter implements GlobalFilter { ...@@ -28,18 +36,51 @@ public class AuthorizationFilter implements GlobalFilter {
@Resource @Resource
private VionConfig vionConfig; private VionConfig vionConfig;
@Resource
private AuthClient authClient;
@Override @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (vionConfig.isEnableAuthorization()) { ServerHttpRequest request = exchange.getRequest();
// todo authorize if (!skip(request)) {
return unAuthorized(exchange.getResponse(), "authorization failed"); if (StringUtils.isNotBlank(vionConfig.getAuthPath())) {
String token = getToken(request);
if (token == null) {
return unAuthorized(exchange.getResponse(), "authorization failed");
}
ImmutablePair<Boolean, String> checkResult = checkToken(token);
Boolean success = checkResult.left;
if (!success) {
return unAuthorized(exchange.getResponse(), checkResult.right);
}
log.info("token 校验成功:{}", token);
}
} }
return chain.filter(exchange); return chain.filter(exchange);
} }
private ImmutablePair<Boolean, String> checkToken(String token) {
// todo authorize
try {
Map<String, String> api = new HashMap<>(2);
api.put("verb", HttpMethod.POST.name());
api.put("path", "/api/v1/auth/authorize");
Map<String, Object> perm = new HashMap<>(2);
perm.put("type", "api");
perm.put("api", api);
JSONObject jsonObject = authClient.checkToken(token, Collections.singletonMap("perm", perm));
} catch (Exception e) {
log.info("token 校验失败:{}", e.getMessage());
return ImmutablePair.of(false, e.getLocalizedMessage());
}
return ImmutablePair.of(true, null);
}
private Mono<Void> unAuthorized(ServerHttpResponse response, String msg) { private Mono<Void> unAuthorized(ServerHttpResponse response, String msg) {
log.info("token校验未通过:{}", msg);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.setStatusCode(HttpStatus.UNAUTHORIZED); response.setStatusCode(HttpStatus.UNAUTHORIZED);
...@@ -48,4 +89,57 @@ public class AuthorizationFilter implements GlobalFilter { ...@@ -48,4 +89,57 @@ public class AuthorizationFilter implements GlobalFilter {
return response.bufferFactory().wrap(bytes); return response.bufferFactory().wrap(bytes);
})); }));
} }
private boolean skip(ServerHttpRequest request) {
List<String> skipAuth = vionConfig.getSkipAuth();
if (CollectionUtils.isEmpty(skipAuth)) {
return false;
}
for (String s : skipAuth) {
String path = request.getPath().toString();
if (path.matches(s)) {
log.info("跳过 token 校验:[{}][{}]", s, path);
return true;
}
}
return false;
}
private String getToken(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst("token");
if (StringUtils.isNotEmpty(token)) {
return token;
}
token = headers.getFirst("authorization");
if (StringUtils.isNotBlank(token)) {
return token;
}
MultiValueMap<String, String> queryParams = request.getQueryParams();
token = queryParams.getFirst("authorization");
if (StringUtils.isNotBlank(token)) {
return token;
}
token = queryParams.getFirst("token");
if (StringUtils.isNotBlank(token)) {
return token;
}
MultiValueMap<String, HttpCookie> cookies = request.getCookies();
HttpCookie auc = cookies.getFirst("authorization");
if (auc != null) {
token = auc.getValue();
if (StringUtils.isNotBlank(token)) {
return token;
}
}
HttpCookie toc = cookies.getFirst("token");
if (toc != null) {
token = toc.getValue();
if (StringUtils.isNotBlank(token)) {
return token;
}
}
return null;
}
} }
package com.viontech.fanxing.forward; package com.viontech.fanxing.forward;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.FilterType;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.ArrayList;
import java.util.List;
/** /**
* . * .
* *
...@@ -16,7 +28,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; ...@@ -16,7 +28,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* @date 2021/6/11 * @date 2021/6/11
*/ */
@SpringBootApplication @SpringBootApplication
@ComponentScan(basePackages = "com.viontech.fanxing",excludeFilters = { @ComponentScan(basePackages = "com.viontech.fanxing", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = com.viontech.fanxing.commons.config.WebConfig.class) @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = com.viontech.fanxing.commons.config.WebConfig.class)
}) })
@EnableDiscoveryClient @EnableDiscoveryClient
...@@ -33,4 +45,30 @@ public class GatewayApp { ...@@ -33,4 +45,30 @@ public class GatewayApp {
} }
} }
@Bean
public Decoder feignDecoder(MyMappingJackson2HttpMessageConverter converter) {
ObjectFactory<HttpMessageConverters> factory = () -> new HttpMessageConverters(converter);
return new OptionalDecoder(
new ResponseEntityDecoder(new SpringDecoder(factory)));
}
@Bean
public MyMappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
return new MyMappingJackson2HttpMessageConverter();
}
@Bean
public HttpMessageConverters httpMessageConverters(MyMappingJackson2HttpMessageConverter converter) {
return new HttpMessageConverters(converter);
}
public static class MyMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public MyMappingJackson2HttpMessageConverter() {
List<MediaType> mediaTypeList = new ArrayList<>(this.getSupportedMediaTypes());
mediaTypeList.add(MediaType.TEXT_PLAIN);
this.setSupportedMediaTypes(mediaTypeList);
}
}
} }
...@@ -18,6 +18,13 @@ spring: ...@@ -18,6 +18,13 @@ spring:
locator: locator:
enabled: true enabled: true
lower-case-service-id: true lower-case-service-id: true
routes:
- id: auth
uri: http://192.168.9.62:20080/
predicates:
- Path=/auth-serv/**
filters:
- RewritePath=/auth-serv/?(?<segment>.*),/$\{segment}
consul: consul:
# 服务发现配置 # 服务发现配置
discovery: discovery:
...@@ -55,6 +62,11 @@ spring: ...@@ -55,6 +62,11 @@ spring:
logging: logging:
config: classpath:logback-${spring.profiles.active}.xml config: classpath:logback-${spring.profiles.active}.xml
vion: vion:
enable-authorization: false auth-path: http://192.168.9.62:20080
skip-auth:
- .*login.*
- .*fanxing-task/register.*
- .*fanxing-task/keepalive.*
- .*fanxing-forward/result.*
redisson: redisson:
path: F:\myIDEAworkspace\jt\fanxing3\fanxing-commons\src\main\resources\redisson.yml path: F:\myIDEAworkspace\jt\fanxing3\fanxing-commons\src\main\resources\redisson.yml
\ No newline at end of file \ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!