gpt4 book ai didi

Spring Boot - 将当前用户存储在全局变量中,并在创建 @service bean 时通过 API 调用进行初始化

转载 作者:行者123 更新时间:2023-12-03 08:39:03 33 4
gpt4 key购买 nike

我正在创建一个以 Zuul 作为网关的微服务架构项目。我在名为 common-service 的服务中处理了所有身份验证。我已经公开了一个来自公共(public)服务的 API 来返回当前登录的用户。这工作正常。

现在,我有另一个名为 inventory 的微服务。在库存的服务类中,我想在多种方法中使用当前登录的用户名。因此,我正在对公共(public)服务进行网络客户端调用并获取当前用户名。这工作正常,但每次我需要用户名时,我都会对公共(public)服务进行网络客户端 API 调用。示例 - 如果我添加一个新条目,执行 API 调用,然后再次更新 API 调用等。这似乎不是一种优化方式

所以问题是 - 我想在全局级别进行此 API 调用。即,每当我的服务 bean 被 Autowiring 时,就应该进行这个 API 调用,并且用户名应该存储在我可以在服务调用中跨方法使用的地方。

我尝试了 @PostConstruct 和 @SessionAttributes 但无法解决确切的问题。

有人可以帮助我找到最适合的解决方案或概念来处理此问题。

下面是代码片段

public class LeadService 
{
@Autowired
WebClient.Builder webClientBuilder;

@Autowired
UserDetailsService userDetailsService;
//more autowiring

private void setLeadFields(Lead lead, @Valid LeadCreateData payload,String type)
{
//some logic
if(type.equalsIgnoreCase("create"))
{
lead.setAsigneeId(userDetailsService.getCurrentUser().getId());
lead.setCreatorId(userDetailsService.getCurrentUser().getId());
}
else if(type.equalsIgnoreCase("update"))
{
//some logic
}

}

private StatusEnum setLeadStatus(Lead lead, StatusEnum status,String string)
{
LeadStatus lstatus=null;
switch(string)
{

case "create":
lstatus = new LeadStatus(lead.getLeadId(),status,userDetailsService.getCurrentUser().getId(),userDetailsService.getCurrentUser().getId());
lsRepo.save(lstatus);
break;
case "udpate":
lstatus= lsRepo.FindLeadStatusByLeadID(lead.getLeadId()).get(0);
if(!lstatus.getStatus().equals(lstatus))
{
lstatus = new LeadStatus(lead.getLeadId(),status,userDetailsService.getCurrentUser().getId(),userDetailsService.getCurrentUser().getId());
lsRepo.save(lstatus);
}
break;
}
return lstatus.getStatus();
}

private Address setAddress(@Valid LeadCreateData payload,Address address)
{
//some setters
address.setCreator(userDetailsService.getCurrentUser().getId());
return aRepo.save(address);
}

如您所见,我在很多地方使用了 userDetailsS​​ervice.getCurrentUser().getId() 。我从下面的 Autowiring 方法中获取这个 id。但每次我需要这个 id 时,都需要调用一次 API。

@Service
public class UserDetailsService
{
@Autowired
WebClient.Builder webClientBuilder;

@Autowired
HttpServletRequest request;

@Value("${common.serverurl}")
private String reqUrl;

public UserReturnData getCurrentUser()
{
UserReturnData userDetails = webClientBuilder.build()
.get()
.uri(reqUrl+"user/me")
.header("Authorization", request.getHeader("Authorization"))
.retrieve()
.bodyToMono(UserReturnData.class)
.block();
return userDetails;
}
}

我想要一种最佳方式,可以调用此 API 方法来仅获取当前用户一次。我可以在我的@service 类中使用它。

最佳答案

  • 创建OncePerPrequestFilterGenericFilterBean其中有您的UserDetailsService自动连线。

  • 您还想创建类似于 RequestContextHolder 的内容或SecurityContextHolder它可以容纳您的UserReturnDataThreadLocal多变的。看看这两个 spring 类来了解一下,但你的可以简单得多。我们称之为UserReturnDataContextHolder .

  • 在您在步骤 1 中创建的过滤器中,当请求到来时填充它,当响应离开时清除它。

  • 现在您可以通过 UserReturnDataContextHolder.getUserReturnData() 在服务中的任何位置访问它并且您也没有调用多个电话

编辑:以下部分由 Sridhar Patnaik 贡献作为引用 -

下面的代码让它工作

添加了一个类来存储当前用户ID

public class CurrentUser 
{
private Long currentUserId;
//getter setter
}

添加了当前用户过滤器来拦截请求并获取当前用户。

public class CurrentUserFilter implements Filter 
{

@Autowired
private CurrentUser currentUser;

@Autowired
UserDetailsService UserDetailsService;

@Override
public void init(FilterConfig arg0) throws ServletException {
// NOOP
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
try
{
this.currentUser.setCurrentUserId(UserDetailsService.getCurrentUser().getId());
chain.doFilter(servletRequest, servletResponse);
}
finally
{
this.currentUser.clear();
}
}

@Override
public void destroy() {
// NOOP
}
}

添加了所需的AppConfig

@Configuration
public class AppConfig
{
@Bean
public Filter currentUserFilter() {
return new CurrentUserFilter();
}

@Bean
public FilterRegistrationBean tenantFilterRegistration() {
FilterRegistrationBean result = new FilterRegistrationBean();
result.setFilter(this.currentUserFilter());
result.setUrlPatterns(Lists.newArrayList("/*"));
result.setName("Tenant Store Filter");
result.setOrder(1);
return result;
}

@Bean(destroyMethod = "destroy")
public ThreadLocalTargetSource threadLocalTenantStore() {
ThreadLocalTargetSource result = new ThreadLocalTargetSource();
result.setTargetBeanName("tenantStore");
return result;
}

@Primary
@Bean(name = "proxiedThreadLocalTargetSource")
public ProxyFactoryBean proxiedThreadLocalTargetSource(ThreadLocalTargetSource threadLocalTargetSource) {
ProxyFactoryBean result = new ProxyFactoryBean();
result.setTargetSource(threadLocalTargetSource);
return result;
}

@Bean(name = "tenantStore")
@Scope(scopeName = "prototype")
public CurrentUser tenantStore() {
return new CurrentUser();
}
}

然后将 CurrentUser 自动连接到我现有的服务类。

{..
@Autowired
CurrentUser currentUser;
...
private void setLeadFields(Lead lead, @Valid LeadCreateData payload,String type)
{
//some logic

if(type.equalsIgnoreCase("create"))
{
lead.setAsigneeId(currentUser.getCurrentUserId());
lead.setCreatorId(currentUser.getCurrentUserId());
lead.setAddress(setAddress(payload, new Address()));
}
else if(type.equalsIgnoreCase("update"))
{
lead.setAsigneeId(userDetailsService.getUserFromId(payload.getAssigneeId()).getId());
lead.setAddress(setAddress(payload,lead.getAddress()));
}

}

关于Spring Boot - 将当前用户存储在全局变量中,并在创建 @service bean 时通过 API 调用进行初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63103867/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com