springboot~某个接口模拟登录并同步给feign
功能
- 某个rest接口是公开的,它的feign服务的接口需要授权
- 重写一个HttpServletRequestWrapper,实现模拟登录之后把header头进行填充
- 接口请求上下文里的token,通过Feign拦截器转给每个feign请求上下文
- 完成对feign接口的自动授权访问
重写HttpServletRequestWrapper
/**
* 自定义的请求上下文.
*/
public class CustomHttpServletRequest extends HttpServletRequestWrapper {
private Map<String, String> headers = new HashMap<>();
public CustomHttpServletRequest(HttpServletRequest request) {
super(request);
}
public void addHeader(String name, String value) {
headers.put(name, value);
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (headers.containsKey(name)) {
value = headers.get(name);
}
return value;
}
@Override
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
names.addAll(headers.keySet());
return Collections.enumeration(names);
}
@Override
public Enumeration<String> getHeaders(String name) {
List<String> list = Collections.list(super.getHeaders(name));
if (headers.containsKey(name)) {
list.add(headers.get(name));
}
return Collections.enumeration(list);
}
}
建立过滤器
@Component
public class CustomFilter implements Filter {
@Autowired
KcUserClient kcUserClient;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
CustomHttpServletRequest request = new CustomHttpServletRequest((HttpServletRequest) servletRequest);
request.addHeader("Authorization", "Bearer " + login().getAccessToken());
filterChain.doFilter(request, servletResponse);
}
public KeycloakAccessToken login() {
// 登陆参数省略
var result = kcUserClient.login(authTokenRequest);
return result;
}
}
WebMvcConfigurer里注册
对/add
接口进行配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private CustomFilter customFilter;
@Bean
public FilterRegistrationBean<CustomFilter> initFilterRegistrationBean() {
FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(customFilter);
registrationBean.addUrlPatterns("/add");
registrationBean.setOrder(0);
return registrationBean;
}
}
Feign拦截器的配置
/**
* @description: Feign内部调用时带上请求头信息
* 注意:要去yml里面改变hystrix Feign的隔离策为strategy: SEMAPHORE
**/
@Configuration
public class FeignConfiguration implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
template.header(name, values);
}
}
Enumeration<String> bodyNames = request.getParameterNames();
StringBuffer body = new StringBuffer();
if (bodyNames != null) {
while (bodyNames.hasMoreElements()) {
String name = bodyNames.nextElement();
String values = request.getParameter(name);
body.append(name).append("=").append(values).append("&");
}
}
if (body.length() != 0) {
body.deleteCharAt(body.length() - 1);
template.body(body.toString());
}
}
}
上面代码完成了对/add接口的拦截,通过自动授权,完成对授权接口kcUserClient.addUser();
调用。
KcUserClient内容
@FeignClient(name = "keycloak", url = "http://192.168.4.26:8080/auth", configuration = KcUserClient.Configuration.class)
public interface KcUserClient {
@PostMapping("/admin/realms/demo/users")
ResponseEntity<?> addUser(@RequestBody UserDTO userDTO);
@RequestMapping(value = "/realms/demo/protocol/openid-connect/token",
method = RequestMethod.POST,
consumes = "application/x-www-form-urlencoded")
KeycloakAccessToken login(@RequestBody AuthTokenRequest authTokenRequest);
/**
* 转向器.
*/
class Configuration {
@Bean
Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> converters) {
return new SpringFormEncoder(new SpringEncoder(converters));
}
}
}
合集:
springboot(1)
分类:
Java
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示