Sri*_*aik 2 spring spring-mvc spring-boot
我正在创建一个以 Zuul 作为网关的微服务架构项目。我在名为 common-service 的服务中处理了所有身份验证。我已经公开了一个来自公共服务的 API 来返回当前登录的用户。这工作正常。
现在,我有另一个微服务,称为库存。在库存的服务类中,我想在多种方法中使用当前登录的用户名。因此,我正在对公共服务进行网络客户端调用并获取当前用户名。这工作正常,但每次我需要用户名时,我都会对公共服务进行网络客户端 API 调用。示例 - 如果我添加一个新条目,执行 API 调用,然后再次更新 API 调用等。这似乎不是一种优化的方式
所以问题是 - 我想在全局级别进行此 API 调用。即,每当我的服务 bean 被自动装配时,就应该进行这个 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);
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我在很多地方使用了 userDetailsService.getCurrentUser().getId() 。我从下面的自动装配方法中获取这个 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;
}
}
Run Code Online (Sandbox Code Playgroud)
我想要一种最佳方法,可以调用此 API 方法来仅获取当前用户一次。我可以在我的@service 课程中使用它。
创建OncePerPrequestFilter
或GenericFilterBean
其中有您的UserDetailsService
自动装配。
而且您还想创建类似于RequestContextHolder
或SecurityContextHolder
可以将您保存UserReturnData
在ThreadLocal
变量中的东西。看看这两个 spring 类来了解一下,但你的可以简单得多。就这样吧UserReturnDataContextHolder
。
在您在步骤 1 中创建的过滤器中,当请求到来时填充它,当响应离开时清除它。
现在您可以通过服务中的任何位置访问它,UserReturnDataContextHolder.getUserReturnData()
并且您也无需进行多次调用
编辑:以下部分由作为Sridhar Patnaik
参考贡献-
下面的代码让它工作
添加了一个类来存储当前用户ID
public class CurrentUser
{
private Long currentUserId;
//getter setter
}
Run Code Online (Sandbox Code Playgroud)
添加了当前用户过滤器来拦截请求并获取当前用户。
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
}
}
Run Code Online (Sandbox Code Playgroud)
添加了必需的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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后将 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()));
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5862 次 |
最近记录: |