我已经搜索过有关此主题的教程,但它们都已过时。任何人都可以向我提供有关将 Spring 安全性集成到 GWT 的任何链接或示例吗?
1 回答
首先,您必须牢记 GWT 应用程序已转换为在客户端运行的 javascript,因此您无法真正保护那里的某些资源。所有敏感信息都应该存储在服务器端(与其他情况一样,不仅仅是 GWT),因此正确的方法是从应用程序服务层的角度考虑 Spring Security 集成,并将该安全性与您的通信协议集成使用 - 在 GWT 的情况下,在大多数情况下它是请求工厂。
解决方案不是很简单,但我无法以更好的方式做到这一点......欢迎任何改进建议。
您需要从创建 GWT 开始ServiceLayerDecorator
,它将请求工厂的世界与 Spring 的世界连接起来。从 ServiceName 注释值中覆盖createServiceInstance
要调用的 Spring 服务类的名称并返回该服务的实例的方法(您需要从 Spring 获取它ApplicationContext
):
final Class<?> serviceClass = requestContext.getAnnotation(ServiceName.class).value();
return appContext.getBean(serviceClass);
此外,您需要重写超类invoke(Method, Object...)
方法以捕获所有抛出的运行时异常。如果是 Spring Security 的实例,则应分析捕获的异常原因AccessDeniedException
。如果是这样,则应重新抛出异常原因。在这种情况下,GWT 不会将异常序列化为字符串,而是将其重新抛出,因此调度程序 servlet 可以通过设置适当的 HTTP 响应状态码来处理它。所有其他类型的异常都会被 GWT 序列化为 String。
实际上,您只能捕获 GWT ReportableException
,但不幸的是它具有包访问修饰符(呵呵...... GWT 不是那么容易扩展的)。捕获所有运行时异常更加安全(虽然不是很优雅,但我们别无选择)——如果 GWT 实现发生变化,这段代码仍然可以正常工作。
现在你需要插入你的装饰器。您可以通过扩展请求工厂 servlet 并定义您的 servlet 构造函数来轻松完成,如下所示:
public MyRequestFactoryServlet() {
this(new DefaultExceptionHandler(), new SpringServiceLayerDecorator());
}
最后一件事——你需要做一个肮脏的黑客攻击并覆盖请求工厂 servlet doPost 方法来改变它处理异常的方式——默认情况下,异常被序列化为字符串,服务器发送 500 个状态码。并非所有异常都应导致 500 sc - 例如,安全异常应导致未经授权的状态代码。所以你需要做的是通过以下方式覆盖异常处理机制:
catch (RuntimeException e) {
if (e instanceof AccessDeniedException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
LOG.log(Level.SEVERE, "Unexpected error", e);
}
}
您可以尝试使用一些“围绕”方面,而不是扩展类 - 在这种情况下,这是更清洁的解决方案。
而已!现在您可以像往常一样使用 Spring Security 注释(@Secured
等等)来注释您的应用程序服务层。
我知道 - 这一切都很复杂,但 Google 的请求工厂很难扩展。伙计们在通信协议方面做得很好,但是这个库的设计很糟糕。当然客户端代码有一些限制(它被编译成java脚本),但服务器端代码可以设计得更好......