使用spring cloud alibaba-网关(gateway)+安全认证(springsecurity+jwt)
上一篇博客开头说到了gateway服务之前调用有些特殊,那是因为webflux和spring-webmvc;gateway不兼容spring-webmvc所以项目创建的时候也就剔除了,剔除之后无法使用HttpServletRequest,所以之前搭建的不能简单的替换zuul,改动太大。只能将zuul从安全认证这个模块中移除,然后独立成一个模块供gateway认证时调用。改造之前的springsec
上一篇博客开头说到了gateway服务之前调用有些特殊,那是因为webflux和spring-webmvc;
gateway不兼容spring-webmvc所以项目创建的时候也就剔除了,剔除之后无法使用HttpServletRequest,所以之前搭建的不能简单的替换zuul,改动太大。只能将zuul从安全认证这个模块中移除,然后独立成一个模块供gateway认证时调用。
改造之前的springsecurity,移除zuul相关依赖,在UserController中新增一个接口
/**
* 认证
* @param token
* @return
*/
@RequestMapping(value = "/verificationToken",method = {RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public ResultVO<Boolean> verificationToken(@RequestParam("token") String token){
AuthUser authUser = JwtUtil.parseToken(token);
authUser.getUsername();
return Backtrack.success(true);
}
此方法供gateway调用,Backtrack为一个统一返回和接收校验的类,用于抛请求异常。
package com.cloudalibaba.securitypermission.common.methods;
import com.cloudalibaba.securitypermission.common.vo.ResultVO;
/**
* 返回和接收校验
* @author wqy
* @version 1.0
* @date 2020/6/9 15:52
*/
public class Backtrack{
/**
* 成功的执行
* @param t 数据体
* @param msg 备注
* @param <T> 泛型
* @return
*/
public static <T> ResultVO<T> success(T t, String msg){
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(10);
resultVO.setData(t);
resultVO.setMsg(msg);
return resultVO;
}
/**
* 成功的执行
* @param t 数据体
* @param <T> 泛型
* @return
*/
public static <T> ResultVO<T> success(T t){
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(10);
resultVO.setData(t);
return resultVO;
}
/**
* 成功的执行
* @param msg 备注
* @param <T> 泛型
* @return
*/
public static <T> ResultVO<T> success(String msg){
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(10);
resultVO.setMsg(msg);
return resultVO;
}
/**
* 失败的执行
* @param t 数据体
* @param msg 备注
* @param <T> 泛型
* @return
*/
public static <T> ResultVO<T> errot(T t,String msg){
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(11);
resultVO.setData(t);
resultVO.setMsg(msg);
return resultVO;
}
/**
* 失败的执行
* @param msg 备注
* @param <T> 泛型
* @return
*/
public static <T> ResultVO<T> errot(String msg){
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(11);
resultVO.setMsg(msg);
return resultVO;
}
/**
* 校验ResultVO结果
* 如果code==10则成功其余则失败
* @param resultVO
* @return
*/
public static <T> T checkData(ResultVO<T> resultVO){
//判断返回结果是否是SuperEntity的子类
//11为异常,失败
if(resultVO.getCode()==11){
throw new RuntimeException(resultVO.getMsg());
}
if(resultVO.getCode()==10){
return resultVO.getData();
}
throw new RuntimeException("调用失败");
}
/**
* 校验ResultVO结果
* 如果code==10则成功其余则失败
* @param resultVO
* @return
*/
public static String checkMsg(ResultVO<String> resultVO){
//判断返回结果是否是SuperEntity的子类
//11为异常,失败
if(resultVO.getCode()==11){
throw new RuntimeException(resultVO.getMsg());
}
if(resultVO.getCode()==10){
return resultVO.getMsg();
}
throw new RuntimeException("调用失败");
}
}
然后修改AccessDeniedHandler和TokenExceptionHandler,这两个类是无权限和token异常
修改response.setContentType为response.setContentType("application/json; charset=utf-8");
这样安全框架这块就算修改完了。
修改gateway,创建上文中的filter文件夹。
并创建一个filter类
package com.cloudalibaba.gateway.filter;
import com.cloudalibaba.gateway.common.methods.Backtrack;
import com.cloudalibaba.gateway.common.vo.ResultVO;
import com.cloudalibaba.gateway.feign.SecuritypePermissionFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
import java.util.List;
/**
* @author wqy
* @version 1.0
* @date 2020/8/1 15:23
*/
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Autowired
private SecuritypePermissionFeign securitypePermissionFeign;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("********come in MyLogGatewayFilter:" + new Date());
ServerHttpRequest request = exchange.getRequest();
System.out.println(request.getPath());
System.out.println(request.getQueryParams());
System.out.println(request.getHeaders().get("token"));
HttpHeaders headers = request.getHeaders();
List<String> strs = headers.get("token");
//获取token并验证
String token = strs.get(0);
System.out.println(token);
Boolean check = Backtrack.checkData(securitypePermissionFeign.verificationToken(token));
System.out.println(check);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
创建feign,指向securitypermission
package com.cloudalibaba.gateway.feign;
import com.cloudalibaba.gateway.common.vo.ResultVO;
import com.cloudalibaba.gateway.config.CustomizedConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author wqy
* @version 1.0
* @date 2020/8/1 16:04
*/
@FeignClient(value = "securitypermission")
public interface SecuritypePermissionFeign {
/**
* 验证token
* @param token
* @return
*/
@RequestMapping(value = "/verificationToken",method = {RequestMethod.POST})
ResultVO<Boolean> verificationToken(@RequestParam("token") String token);
}
这样按正常来说是可以进行调用了,但是!!!,这个是gateway,这样会报错(HttpMessageConverters),请求没问题,但是接受返回值的时候问题就来了,gateway没有对应的解析器去解析response(也可能是默认用错了解析器)。所以要进行一个转换。
package com.cloudalibaba.gateway.config;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import reactor.core.publisher.Mono;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 转换器
* gateway通过feign调用的时候,gateway中没有相应的解析器(返回),所以会出现异常(HttpMessageConverters)
* 然后将请求转成HttpMessageConverters即可
* @author wqy
*/
@Configuration
public class GatewayConfig {
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress());
}
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
}
这样就可以正常的访问了。
最后奉上代码
更多推荐
所有评论(0)