feat:演示环境禁止删除和修改

This commit is contained in:
haoxr 2021-01-30 00:40:26 +08:00
parent 110001db88
commit 07233324cc
7 changed files with 65 additions and 47 deletions

View File

@ -68,7 +68,6 @@
<version>${youlai.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
@ -98,12 +97,6 @@
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- spring cloud 2020.0.0内置的openfeign3.0.0和spring cloud alibaba框架nacos、seata冲突临时解决方案-->
<dependency>
<groupId>org.springframework.cloud</groupId>
@ -154,13 +147,13 @@
<version>1.0.0</version>
<executions>
<!--执行mvn package,即执行 mvn clean package docker:build-->
<!-- <execution>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>-->
</execution>
</executions>
<configuration>

View File

@ -49,6 +49,8 @@ public interface AuthConstants {
String JWT_CLIENT_ID_KEY = "client_id";
String JWT_JTI_KEY = "client_id";
/**
* JWT存储权限前缀
*/

View File

@ -27,8 +27,10 @@ public enum ResultCode implements IResultCode, Serializable {
CLIENT_AUTHENTICATION_FAILED("A0212","客户端认证失败"), // *
TOKEN_INVALID_OR_EXPIRED("A0230","token无效或已过期"),
USER_AUTHORIZED_ERROR ("A0300","访问权限异常"),
USER_ACCESS_UNAUTHORIZED ("A0301","访问未授权"),
AUTHORIZED_ERROR ("A0300","访问权限异常"),
ACCESS_UNAUTHORIZED ("A0301","访问未授权"),
FORBIDDEN_OPERATION ("A0302","演示环境禁止修改、删除重要数据,请本地部署后测试"),
USER_REQUEST_PARAM_ERROR("A0400","用户请求参数错误"),
USER_REQUEST_PARAM_IS_BLANK("A0410","请求必填参数为空"),

View File

@ -68,7 +68,6 @@
<version>${youlai.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>

View File

@ -6,6 +6,7 @@ import com.youlai.common.core.constant.AuthConstants;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import com.youlai.gateway.security.AuthorizationManager;
import com.youlai.gateway.util.WebUtils;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -66,16 +67,7 @@ public class ResourceServerConfig {
ServerAccessDeniedHandler accessDeniedHandler() {
return (exchange, denied) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.failed(ResultCode.USER_ACCESS_UNAUTHORIZED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
.flatMap(response ->WebUtils.writeFailedToResponse(response,ResultCode.ACCESS_UNAUTHORIZED));
return mono;
};
@ -88,16 +80,7 @@ public class ResourceServerConfig {
ServerAuthenticationEntryPoint authenticationEntryPoint() {
return (exchange, e) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
.flatMap(response -> WebUtils.writeFailedToResponse(response,ResultCode.TOKEN_INVALID_OR_EXPIRED));
return mono;
};
}

View File

@ -7,16 +7,20 @@ import com.nimbusds.jose.JWSObject;
import com.youlai.common.core.constant.AuthConstants;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import com.youlai.gateway.util.WebUtils;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -28,43 +32,53 @@ import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* 黑名单token过滤器
* 全局过滤器
*/
@Component
@Slf4j
@AllArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Autowired
private RedisTemplate redisTemplate;
// 是否演示环境
@Value("${demo}")
private Boolean isDemoEnvironment;
@SneakyThrows
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 演示环境禁止删除和修改
if (isDemoEnvironment && (HttpMethod.PUT.toString().equals(request.getMethodValue()) ||
HttpMethod.DELETE.toString().equals(request.getMethodValue())
)) {
log.warn(ResultCode.FORBIDDEN_OPERATION.getMsg());
return WebUtils.writeFailedToResponse(response, ResultCode.FORBIDDEN_OPERATION);
}
// 无token放行
String token = exchange.getRequest().getHeaders().getFirst(AuthConstants.JWT_TOKEN_HEADER);
if (StrUtil.isBlank(token)) {
return chain.filter(exchange);
}
// 解析JWT获取jti以jti为key判断redis的黑名单列表是否存在存在拦截响应token失效
token = token.replace(AuthConstants.JWT_TOKEN_PREFIX, Strings.EMPTY);
JWSObject jwsObject = JWSObject.parse(token);
String payload = jwsObject.getPayload().toString();
// 黑名单token(登出修改密码)校验
JSONObject jsonObject = JSONUtil.parseObj(payload);
String jti = jsonObject.getStr("jti"); // JWT唯一标识
String jti = jsonObject.getStr(AuthConstants.JWT_JTI_KEY);
Boolean isBlack = redisTemplate.hasKey(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti);
if (isBlack) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer));
return WebUtils.writeFailedToResponse(response, ResultCode.TOKEN_INVALID_OR_EXPIRED);
}
ServerHttpRequest request = exchange.getRequest().mutate()
// 存在token且不是黑名单request写入JWT的载体信息
request = exchange.getRequest().mutate()
.header(AuthConstants.JWT_PAYLOAD_KEY, payload)
.build();
exchange = exchange.mutate().request(request).build();

View File

@ -1,9 +1,34 @@
package com.youlai.gateway.util;
import cn.hutool.json.JSONUtil;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* @Author haoxr
* @Date 2021-01-29 13:30
* @Version 1.0.0
*/
public class WebUtils {
public static Mono writeFailedToResponse(ServerHttpResponse response,ResultCode resultCode){
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.failed(resultCode));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
}
}