我搜索了有关此主题的教程,但所有这些都已过时。任何人都可以向我提供有关将Spring安全性集成到GWT中的任何链接或示例吗?
答案 0 :(得分:3)
首先,您必须记住GWT应用程序已转换为在客户端运行的javascript,因此您无法确保在那里保护一些资源。所有敏感信息都应存储在服务器端(如同其他情况一样,不仅仅适用于GWT),因此正确的方法是从应用服务层的角度考虑Spring Security集成,并将该安全性与通信协议集成在一起使用 - 在GWT的情况下,在大多数情况下是请求工厂。
解决方案不是很简单,但我不能以更好的方式做到这一点......欢迎提出任何改进建议。
您需要首先创建GWT ServiceLayerDecorator
,它将请求工厂的世界与Spring世界连接起来。覆盖createServiceInstance
方法,从ServiceName注释值调用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 s.c - 例如安全异常会导致未经授权的状态代码。因此,您需要做的是以下列方式覆盖异常处理机制:
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);
}
}
不是扩展类,而是尝试使用一些'around'方面 - 在这种情况下它是更清晰的解决方案。
就是这样!现在,您可以像往常一样使用Spring Security注释(@Secured
等)注释您的应用程序服务层。
我知道 - 这一切都很复杂,但Google的请求工厂难以扩展。伙计们做了很多关于通信协议的工作,但是这个库的设计非常糟糕。当然客户端代码有一些限制(它编译为java脚本),但服务器端代码可以设计得更好......