我正在开发一个Java EE web应用程序,在该应用程序中我使用Spring MVC和Spring安全性。到目前为止,我成功地使用自定义userService(从我的数据库中检索信息)实现了常见的安全功能,但我现在面临着一个新的安全问题,我真的不知道解决它的最佳方法是什么…
以下是我需要做的:在我的应用程序中经过身份验证的用户可以浏览他们的项目,但只能打开他们有权访问的项目(并打开里面的内容),而不能打开其他项目。
我目前的实现是通过导航(用户界面)来处理它的,只向用户提供授权项目的列表。但是,如果一个聪明的用户直接编辑URL以打开具有另一个id的项目,那么就不会对项目id进行授权测试,用户也会这样做,从而顺利打开项目。
因此,我想添加的是一个控件,用于处理打开项目或其中某些内容的每个请求。该控件将测试当前用户是否可以打开请求的项目id。否则,它将向用户返回一个拒绝访问的页面。这个控件本身很容易实现,但由于它是一段代码,可能存在于我的应用程序的许多方法中,我想找到最干净的方法!
你认为实现这一点的最佳方式是什么?我考虑了几种可能性,但我需要建议:
1) 使用servlet过滤器?
2) 使用自定义authenticationManager添加对Spring安全性的特殊访问?类似于:
<security:intercept-url pattern="/open*" access="canOpen()" />
(但我不确定如何定义这个,以及我是否能够从原始请求中获得参数…)
3) 使用面向方面编程?(但我在某个地方读到它对控制器调用不起作用)
4) 使用弹簧拦截器?
5) 其他想法?
提前感谢您的帮助!
我建议您使用自定义的PermissionEvaluator,这样您基本上可以在网页和控制器中使用相同的实现:
在您可以使用的网页中:<security:authorize access="hasPermission(#project,'read')"></security:authorize>
在控制器中以及在您可以用的任何服务方法中:@PreAuthorize("hasPermission(#project,'read')")
或者@PostAuthorize
和@PostFilter("hasPermission(filterObject,'read')")
(用于列表)
所有这些函数都将根据您自己的权限评估器来限制访问或筛选结果列表。它们都指向相同的实现,看起来像这样:
@Component
public class MyPermissionEvaluator implements PermissionEvaluator {
private final Log logger = LogFactory.getLog(getClass());
@Override
public boolean hasPermission(Authentication auth, Object arg1, Object arg2) {
logger.info("hasPermission "+auth+" - "+arg1+" - "+arg2+" ");
if(arg2 instanceof String && arg1 instanceof MyProject){
MyProject project = (MyProject)arg1;
if(((String) arg2).equals("read")){
boolean result = hasPermissionReadProject(auth, project);
return result;
}
}
return false;
}
@Override
public boolean hasPermission(Authentication arg0, Serializable arg1,
String arg2, Object arg3) {
logger.info("hasPermission "+arg0+" - "+arg1+" - "+arg2+" - "+arg3+" ");
return false;
}
}
此外,当这些方法返回false时,它会自动抛出AccessDeniedException,您可以轻松地将其配置为重定向到http元素中自己的accessDenied页面:
<http auto-config="true">
<intercept-url pattern="/admin*" access="ROLE_ADMIN" />
<access-denied-handler error-page="accessDeniedPage"/>
</http>
我没有使用Spring Security,但我不得不面对类似的情况。
我选择实现数据库访问验证。我的每个请求都有一个内置的用户/数据确认。也许这不是最简单的方法,但通过这种方式,用户只能请求他们可以读/写的数据。我从来没有遇到过任何麻烦。
我的请求适用于已登录的用户角色。例如,在我的案例中,如果用户是学生,他只能访问自己的文件夹,但如果是老师,他可以访问他所教学生的文件夹。
请求(简化了很多!)[与IBatis]:
SELECT *
FROM FOLDER F
<dynamic prepend="WHERE">
<isNotEmpty property="user">
<isEqual property="user.role" compareValue="student">
F.ID_STUDENT = #user.idStudent:NUMERIC#
</isEqual>
<isEqual property="user.role" compareValue="teacher">
F.ID_STUDENT IN
(SELECT ID_STUDENT
FROM CLASSES
WHERE ID_TEACHER = #user.id:NUMERIC#)
</isNotEmpty>
</isNotEmpty>
<isEmpty property="user">
F.ID IS NULL
</isEmpty>
</dynamic>