【问题标题】:Spring boot - Pass argument from interceptor to method in controllerSpring boot - 将参数从拦截器传递给控制器​​中的方法
【发布时间】:2020-03-15 11:27:02
【问题描述】:

出于学习目的,我制作了一个自定义身份验证系统,我通过Authorization 标头将令牌从客户端传递到服务器。

在服务器端,我想知道是否可以在拦截器中,在请求到达控制器中的方法之前,创建一个带有来自令牌的电子邮件作为属性的用户对象,然后传递这个用户反对我需要的每个请求。

这是我想要得到的,例如:

@RestController
public class HelloController {

    @RequestMapping("/")
    public String index(final User user) {
        return user.getEmail();
    }

}

public class User {
    private String email;
}

其中 user 是我在预拦截器中使用请求 Authorization 标头创建的对象,然后我可以传递或不传递给 RestController 中的任何方法。

这可能吗?

【问题讨论】:

  • 这是个好问题

标签: spring spring-boot spring-mvc interceptor


【解决方案1】:

推荐解决方案

我将创建一个带有@Scope 请求的@Bean 请求,该请求将持有用户,然后将适当的实体放入该持有人,然后在方法内从该持有人获取。

@Component
@Scope("request")
public class CurrentUser {
    private User currentUser;

    public User getCurrentUser() {
        return currentUser;
    }

    public void setCurrentUser(User currentUser) {
        this.currentUser = currentUser;
    }
}

然后

@Component
public class MyInterceptor implements HandlerInterceptor {

   private CurrentUser currentUser;

   @Autowired
   MyInterceptor(CurrentUser currentUser) {
       this.currentUser = currentUser;
   }

   @Override
   public boolean preHandle(
      HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      this.currentUser.setCurrentUser(new User("whatever"));
      return true;
   }
}

在控制器中

@RestController
public class HelloController {

    private CurrentUser currentUser;

    @Autowired
    HelloController(CurrentUser currentUser) {
        this.currentUser = currentUser;
    }

    @RequestMapping("/")
    public String index() {
        return currentUser.getCurrentUser().getEmail();
    }

}

替代解决方案

如果您想要的对象只包含一个字段,您可以作弊并将该字段添加到HttpServletRequest 参数中,然后就可以看到奇迹发生了。

@Component
public class MyInterceptor implements HandlerInterceptor {
   @Override
   public boolean preHandle(
      HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      //TRY ONE AT THE TIME: email OR user
      //BOTH SHOULD WORK BUT SEPARATELY OF COURSE
      request.setAttribute("email", "login@domain.com");
      request.setAttribute("user", new User("login@domain.com"));
      return true;
   }
}

【讨论】:

  • 有没有办法做我在我的例子中提出的?我非常喜欢这种方式,我曾在一个使用 Google Cloud Endpoints 和 Google Sign-in 的项目中看到它
  • @UlisesCT 请尝试一下我刚刚添加到答案中的内容
  • 我会认真考虑这个解决方案@UlisesCT。它比您想要的有一个很大的优势:您可以将当前用户注入到处理请求所涉及的任何 bean 中。因此,例如,如果您在服务层中需要它,则无需在方法之间传递它。您只需注入 CurrentUser bean。但是是的,您可以将用户存储在拦截器的请求属性中,并在控制器方法中使用@RequestAttribute
  • @UlisesCT 请查看完整答案
  • @AlexLipov 从我的回答中查看替代解决方案 - 它不涉及范围。但是,可以使用称为 ScopedProxy 的技术在单例 bean 中拥有一个请求范围的 bean
猜你喜欢
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-09
  • 2014-07-21
  • 1970-01-01
  • 2013-08-21
相关资源
最近更新 更多