日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gateway权限统一认证

發(fā)布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gateway权限统一认证 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言:

? 之前使用過JWT TOKEN, 所生成的TOKEN過于繁瑣, 且在用戶維度操作上并不能滿足業(yè)務(wù)需求.

JWT TOKEN自刷新,請點(diǎn)擊此文章了解!

自定義TOKEN實(shí)現(xiàn)流程圖:

需求:

1. Token過期時間為60分鐘, 若用戶正在持續(xù)操作則應(yīng)該為token續(xù)期 2. 當(dāng)用戶登陸后,應(yīng)該可以根據(jù)Token獲取對應(yīng)的用戶,且在系統(tǒng)中用戶只能在一個地方登陸 3. Token對應(yīng)的權(quán)限應(yīng)該可以進(jìn)行統(tǒng)一鑒權(quán)

創(chuàng)建Token數(shù)據(jù)模型:

/* token 數(shù)據(jù)模型 */ public Token {//UUID => TOKEN => Redis KEYprivate String key;//用戶信息 => Redis VALUEprivate User user;// 創(chuàng)建token時間戳private Long createTimestamp;// 當(dāng)前token所對應(yīng)的sessionId;private String sessionId;/* 省略 get set 方法 */ } /* 用戶數(shù)據(jù)模型 */ public User {private String name;private String age;private String gender;// 權(quán)限路徑列表private List<String> permissions;/* 省略 get set 方法 */ }

gateway攔截器:

/*** @author zly*/ @Slf4j @Configuration public class HttpRequestFilter implements GlobalFilter, Ordered {@Resourceprivate RedisService redisService;@Resourceprivate WhiteListProperties whiteListProperties;@Value("${spring.profiles.active}")private String env;private final static Long TIME_OUT = 1800000L;/*** 登錄KEY前綴*/private static final String LOGIN_KEY = "LOGIN_KEY";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest serverHttpRequest = exchange.getRequest();String path = serverHttpRequest.getURI().getPath();String url = null;try {boolean res = false;String[] paths = path.split("/");if ("api".equals(paths[3])) {res = this.isCheckToken(path.split("api")[1]);} else {res = this.isCheckToken(paths[3]);}if (res) {url = path.split("api")[1];}} catch (Exception e) {// nothing}/* 參數(shù)校驗(yàn) */this.checkParams(serverHttpRequest.getQueryParams());/* 權(quán)限校驗(yàn) */if (StringUtils.isNotBlank(url)) {/* 校驗(yàn)請求token是否過期 */UserVO user = this.checkToken(serverHttpRequest);/* 白名單 */if (!whiteListProperties.getWhiteList().contains(url)) {/* 校驗(yàn)權(quán)限 */this.checkPermission(url, user.getPermissionUrls());}}return chain.filter(exchange);}private boolean isCheckToken(String path) {List<String> notCheckToken = whiteListProperties.getNotCheckToken();for (String url : notCheckToken) {if (url.contains(path)) {return false;}}return true;}private UserVO checkToken(ServerHttpRequest serverHttpRequest) {String token = serverHttpRequest.getHeaders().getFirst("token");ObjectMapper objectMapper = new ObjectMapper();Object key = redisService.getKey(LOGIN_KEY + token);if (Objects.isNull(key)) {throw new AuthException("登錄超時,請重新登錄!");}UserVO user = objectMapper.convertValue(key, UserVO.class);if (System.currentTimeMillis() - user.getTimestamp() > TIME_OUT) {/* 取出記錄的時間戳與當(dāng)前時間對比 若大于半小時則更新緩存,自動續(xù)期 */user.setTimestamp(System.currentTimeMillis());redisService.insert(LOGIN_KEY + token, user, 60, TimeUnit.MINUTES);}return user;}@Overridepublic int getOrder() {return 0;}/*** 參數(shù)校驗(yàn)** @param params 參數(shù)Map*/private void checkParams(MultiValueMap<String, String> params) {params.forEach((k, v) -> {String param = v.toString().toUpperCase();if (param.contains(ASTERISK) || param.contains(SINGLE_QUOTES)|| param.contains(WITH) || param.contains(QUESTION_MARK)|| param.contains(AND) || param.contains(SELECT)|| param.contains(OR) || param.contains(WHERE)|| param.contains(DROP) || param.contains(UPDATE)|| param.contains(SET) || param.contains(DELETE)|| param.contains(FROM) || param.contains(INSERT)|| param.contains(ILLEGAL_CHARACTER)) {throw new IllegalCharacterException("輸入非法參數(shù) : " + v.toString());}});}/*** 權(quán)限校驗(yàn)** @param url 訪問路徑*/private void checkPermission(String url, List<String> permissionUrls) {/* 開發(fā)環(huán)境省略權(quán)限校驗(yàn) */if ("dev".equals(env)){return;}/* 權(quán)限路徑匹配 */for (String permissionUrl : permissionUrls) {if (url.contains(permissionUrl)) {return;}}throw new ServiceException("權(quán)限不足!");} }

異常攔截并統(tǒng)一返回:

/*** 覆蓋默認(rèn)的異常處理** @author yinjihuan*/ @Configuration @EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class}) public class ErrorHandlerConfiguration {private final ServerProperties serverProperties;private final ApplicationContext applicationContext;private final ResourceProperties resourceProperties;private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public ErrorHandlerConfiguration(ServerProperties serverProperties,ResourceProperties resourceProperties,ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer,ApplicationContext applicationContext) {this.serverProperties = serverProperties;this.applicationContext = applicationContext;this.resourceProperties = resourceProperties;this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes,this.resourceProperties,this.serverProperties.getError(),this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());return exceptionHandler;}}

自定義用戶認(rèn)證異常:

/*** 自定義異常處理** <p>異常時用JSON代替HTML異常信息<p>** @author yinjihuan*/ public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,ErrorProperties errorProperties, ApplicationContext applicationContext) {super(errorAttributes, resourceProperties, errorProperties, applicationContext);}/*** 獲取異常屬性*/@Overrideprotected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {int code = HttpStatus.INTERNAL_SERVER_ERROR.value();Throwable error = super.getError(request);/* 處理全局自定義異常類攔截 */if (error instanceof org.springframework.cloud.gateway.support.NotFoundException) {code = HttpStatus.NOT_FOUND.value();}if (error instanceof com.wisdom.pojo.exception.IllegalUrlException) {code = HttpStatus.BAD_REQUEST.value();}if (error instanceof com.wisdom.pojo.exception.IllegalCharacterException) {code = HttpStatus.NOT_ACCEPTABLE.value();}if (error instanceof com.wisdom.pojo.exception.AuthException) {code = HttpStatus.UNAUTHORIZED.value();}if (error instanceof com.wisdom.pojo.exception.ServiceException) {return response(HttpStatus.OK.value(), HttpStatus.BAD_REQUEST.value(), error.getMessage());}if (error instanceof org.springframework.web.server.ResponseStatusException) {code = HttpStatus.NOT_FOUND.value();}if (error instanceof com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException) {return response(HttpStatus.OK.value(), HttpStatus.SERVICE_UNAVAILABLE.value(),"訪問頻率過高,請稍后訪問!");}if (error instanceof com.alibaba.csp.sentinel.slots.block.flow.FlowException) {return response(HttpStatus.OK.value(), HttpStatus.SERVICE_UNAVAILABLE.value(),"訪問頻率過高,請稍后訪問!");}return response(code, code, this.buildMessage(request, error));}/*** 指定響應(yīng)處理方法為JSON處理的方法** @param errorAttributes 錯誤屬性*/@Overrideprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);}/*** 根據(jù)code獲取對應(yīng)的HttpStatus** @param errorAttributes 錯誤屬性* @return httpStatus*/@Overrideprotected int getHttpStatus(Map<String, Object> errorAttributes) {int statusCode = (int) errorAttributes.get("http-code");HttpStatus httpStatus = HttpStatus.valueOf(statusCode);return httpStatus.value();}/*** 構(gòu)建異常信息** @param request 請求域* @param ex 錯誤類* @return String*/private String buildMessage(ServerRequest request, Throwable ex) {StringBuilder message = new StringBuilder("Failed to handle request [");message.append(request.methodName());message.append(" ");message.append(request.uri());message.append("]");if (ex != null) {message.append(": ");message.append(ex.getMessage());}return message.toString();}/*** 構(gòu)建返回的JSON數(shù)據(jù)格式** @param status 狀態(tài)碼* @param errorMessage 異常信息* @return Map*/public static Map<String, Object> response(int httpCode, int status, String errorMessage) {Map<String, Object> map = new HashMap<>(3);map.put("http-code", httpCode);map.put("code", status);map.put("message", errorMessage);map.put("data", null);return map;}}

源碼地址:

在線自定義TOKEN源碼地址

總結(jié)

以上是生活随笔為你收集整理的gateway权限统一认证的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。