首先,这个问题总体上表明对“REST Web 服务”的目的存在误解。该问题具体要求使用 REST Web 服务执行两个相当不寻常的任务:
- 操纵与请求关联的 HTTP 会话。
- 重定向到由有状态 MVC 框架管理的 HTML 页面作为响应。
两者都与 REST 的 stateless 本质完全矛盾。这些任务不应该由 REST Web 服务执行。此外,REST Web 服务主要供编程客户端(例如 JavaScript 或 Java 代码)使用,而不是供使用 HTML 页面的 Web 浏览器使用。您通常不会在浏览器的地址栏中输入 REST Web 服务的 URL 来查看 HTML 页面。您通常在浏览器的地址栏中输入 HTML 页面的 URL。该 HTML 页面又可以由基于 HTML 表单的 MVC 框架(例如 JSF)生成。
在您的具体情况下,在程序化客户端检索到唯一
来自 REST Web 服务的 ID,然后程序化客户端应该依次向 JSF Web 应用程序发出一个新请求。例如。在基于 Java 的客户端中如下所示(下面的示例假设它是一个普通的 servlet,但它可以是您自己所说的任何其他内容):
String uniqueId = restClient.getUniqueId(userId, token);
String url = "http://example.com/context/login.xhtml?uniqueId=" + URLEncoder.encode(uniqueId, "UTF-8");
response.sendRedirect(url);
在目标 JSF Web 应用程序中,只需按照通常的方式使用 <f:viewParam>/<f:viewAction> 即可获取唯一 ID 并基于该 ID 执行业务操作。例如。如下login.xhtml:
<f:metadata>
<f:viewParam name="uniqueId" value="#{authenticator.uniqueId}" />
<f:viewAction action="#{authenticator.check}" />
</f:metadata>
@ManagedBean
@RequestScoped
public class Authenticator {
private String uniqueId;
@EJB
private UserService service;
public String check() {
FacesContext context = FacesContext.getCurrentInstance();
User user = service.authenticate(uniqueId);
if (user != null) {
context.getExternalContext().getSessionMap().put("user", user);
return "/somehome.xhtml?faces-redirect=true";
}
else {
context.addMessage(null, new FacesMessage("Invalid token"));
return null; // Or some error page.
}
}
// Getter/setter.
}
也许为了方便起见,REST Web 服务甚至可以返回包含唯一 ID 的完整 URL,这样客户端就不必担心目标 URL。
String uniqueIdURL = restClient.getUniqueIdURL(userId, token);
response.sendRedirect(uniqueIdURL);
另一方面,您很有可能只是误解了功能需求,您可以直接在 JSF Web 应用程序中处理用户 ID 和令牌,如果它与 REST Web 运行在同一台服务器上,则更有可能服务,也使用 HTTPS。只需添加一个额外的<f:viewParam> 并在<f:viewAction> 方法中执行与JAX-RS 资源相同的业务服务逻辑。
<f:metadata>
<f:viewParam name="userId" value="#{authenticator.userId}" />
<f:viewParam name="token" value="#{authenticator.token}" />
<f:viewAction action="#{authenticator.check}" />
</f:metadata>
另见: