使用最新的 Spring Cloud 和 Spring Boot,我得到了带有 Zuul 网关的微服务布局。当用户发送 get 请求时,他们的 JWT token 会添加到请求中,然后发送到微服务,在微服务中对他们进行身份验证,一切照常进行。这一切都很完美。
在处理 POST/PATCH/DELETE 请求时,我遇到了一些困难。这些不会直接进入它们预定的微服务,而是进入消息队列。该队列包含一个简单的 POJO,其中包含一个任务和有关要执行的任务的信息,以及用户 JWT。
当接收微服务从队列中获取消息并开始处理它时,从技术上讲,用户并没有像使用 GET 请求那样登录到微服务。这使得做需要知道用户是谁的事情变得困难。当然,每次我需要知道这个人是谁时,我都可以查找他们,但这看起来很笨拙。
我考虑过为 POST/PATCH/DELETE 命令创建一个 REST Controller ,并让队列监听器从这些命令中调用自身,从任务中添加 token 。就 Spring 安全性而言,这实际上与 GET 请求相同。
这是正确的模式吗?或者是否有一种简单的编程方式来使用 JWT 登录用户?我看过一些使用用户名/密码的示例,但不确定如何将其转录为使用 JWT。
最佳答案
谢谢Andy Brown为了确认我这样做并不是完全疯了。对于任何感兴趣的人来说,这是一个非常简单的解决方案,如下所示:
队列服务只是监听事件(在本例中是来自 AWS SQS),一旦事件通过,它就会被发送到命令 Controller 进行处理。
@Service
@EnableSqs
public class QueueListener {
private final static String SERVICE = "http://instance-service/instances";
@Autowired
private JsonTransformService jsonTransformService;
@Autowired
private RestTemplate restTemplate;
@MessageMapping("${queues.instanceEvents}")
public void instanceCommandHandler(String payload) {
// Transform the payload to the object so we can get the preset JWT
Instance instance = jsonTransformService.read(Instance.class, payload);
// Load the JWT into the internal request header, without this a 403 is thrown
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + instance.getUserToken());
HttpEntity<String> instanceEntity = new HttpEntity<>(payload, headers);
// Decide and set where to fire the request to
String endpoint;
switch (instance.getSwordfishCommand()) {
case "start": {
endpoint = "/start";
break;
}
case "stop": {
endpoint = "/stop";
break;
}
case "create": {
endpoint = "/create";
break;
}
case "reboot": {
endpoint = "/reboot";
break;
}
case "terminate": {
endpoint = "/terminate";
break;
}
default: {
endpoint = "/error";
}
}
// Fire the initial string payload through to the correct controller endpoint
restTemplate.exchange(SERVICE + endpoint, HttpMethod.POST, instanceEntity, String.class);
}
}
还有一个非常简单的 REST Controller 来执行任务
@RestController
@RequestMapping("/instances")
public class InstanceCommandController {
@Autowired
private EC2Create ec2Create;
@Autowired
private EC2Start ec2Start;
@Autowired
private EC2Stop ec2Stop;
@Autowired
private EC2Reboot ec2Reboot;
@Autowired
private EC2Terminate ec2Terminate;
@Autowired
private JsonTransformService jsonTransformService;
@PostMapping("/create")
public void create(@RequestBody String payload) {
ec2Create.process(jsonTransformService.read(Instance.class, payload));
}
@PostMapping("/start")
public void start(@RequestBody String payload) {
ec2Start.process(jsonTransformService.read(Instance.class, payload));
}
@PostMapping("/stop")
public void stop(@RequestBody String payload) {
ec2Stop.process(jsonTransformService.read(Instance.class, payload));
}
@PostMapping("/reboot")
public void reboot(@RequestBody String payload) {
ec2Reboot.process(jsonTransformService.read(Instance.class, payload));
}
@PostMapping("/terminate")
public void terminate(@RequestBody String payload) {
ec2Terminate.process(jsonTransformService.read(Instance.class, payload));
}
}
这很好地遵循了 CQRS 模式,同时仍然在每次调用时对用户进行身份验证。对我来说这非常有用,因为我有一个 AmazonEC2Async 客户端,它在每个请求中使用用户自己的访问权限和 secret token 。
欢呼帮助!
关于java - 实现 CQRS 模式时如何使用 Spring 处理 JWT 身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48102816/