我按照Krams Spring Security 3教程实现了Spring ACL(链接:krams915.blogspot.com/2011/01/spring-security-3-full-acl-tutorial.html)。我基本上把他的代码粘贴到了我的代码中。我希望我能有一个可以扩展的工作范例。代码运行但是has权限方法永远不会被调用,也不会抛出任何异常。
我使用Postgres 9作为我的数据库。我使用Spring ACL文档中的DDL来实现模式。
我的Spring Security配置文件如下所示:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:arg="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/public" access="hasRole('anonymousReader')" requires-channel="https" />
<security:intercept-url pattern="/public/*" access="hasRole('anonymousReader')" requires-channel="https" />
<security:intercept-url pattern="/bulletin/view" access="hasRole('anonymousReader')"/>
<security:intercept-url pattern="/role/admin" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/role/user" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/role/visitor" access="hasRole('anonymousReader')"/>
<!-- URLs that are accessed by role/actions -->
<security:intercept-url pattern="/**" requires-channel="https" />
<!-- Defines a custom role in place of ROLE_ANONYMOUS. ROLE_ANONYMOUS will no more work, use ROLE_GUEST instead of it-->
<security:anonymous username="guest" granted-authority="anonymousReader" />
<!-- login/logout forms -->
<security:form-login login-page="/public" default-target-url="/member/registerLogin"
authentication-failure-url="/public/loginfailed" />
<security:logout invalidate-session="true" logout-success-url="/public" />
</security:http>
<security:authentication-manager alias="authManager">
<!-- security:authentication-provider user-service-ref="customUserDetailsServiceSparql" -->
<security:authentication-provider user-service-ref="customUserDetailsServiceJPA">
<!-- should the auth module go in the tripple store ??? -->
<security:password-encoder hash="plaintext"/>
<!-- security:password-encoder ref="encoder"/ -->
</security:authentication-provider>
</security:authentication-manager>
<!-- bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/ -->
<bean id="anonymousAuthFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter" arg:key="guest" />
<bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider" arg:key="guest" />
</beans>
My Spring ACL配置如下所示(除了更改数据源并将guest虚拟机角色更改为匿名阅读器之外,此文件已从Krams教程中保持不变地剪切和粘贴。):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<!-- Enables method security with expression-based access control -->
<security:global-method-security pre-post-annotations="enabled">
<!-- Reference to a custom expression handler with ACL support -->
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<!-- A customized expression handler
permissionEvaluator: a reference to a custom PermissionEvaluator
roleHierarchy: defines the role order -->
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"
p:permissionEvaluator-ref="permissionEvaluator"
p:roleHierarchy-ref="roleHierarchy" />
<!-- A customized PermissionEvaluator that evaluates permissions via the ACL module -->
<bean class="org.springframework.security.acls.AclPermissionEvaluator" id="permissionEvaluator">
<!-- Reference to the ACL service which performs JDBC calls to an ACL database -->
<constructor-arg ref="aclService"/>
</bean>
<!-- A customized ACL service which provides default JDBC implementation -->
<bean class="org.springframework.security.acls.jdbc.JdbcMutableAclService" id="aclService">
<constructor-arg ref="connectionPoolDataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<!-- A lookup strategy for optimizing database queries -->
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="connectionPoolDataSource"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg ref="auditLogger"/>
</bean>
<!-- An ACL cache to minimize calls to the ACL database -->
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
</bean>
<!-- An ACL authorization strategy to determine whether a principal is permitted to call administrative methods -->
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
</list>
</constructor-arg>
</bean>
<!-- An audit logger used to log audit events -->
<bean id="auditLogger" class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
<!-- Defines the role order -->
<!-- http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.html -->
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_USER
ROLE_USER > anonymousReader
</value>
</property>
</bean>
</beans>
我将这两个文件从web.xml文件加载到Spring上下文中。这两个文件都是成功加载的。以下是上下文参数:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
WEB-INF/mvc-dispatcher-servlet.xml,
WEB-INF/acl-context.xml,
WEB-INF/spring-security-context.xml,
WEB-INF/resources-context.xml
</param-value>
</context-param>
我更改了他的控制器以使用磁贴并使服务在内存对象中使用而不是转到数据库。内存对象具有预期的长ID值。以下是代码示例。
一个。公告控制器:
/**
* Handles Bulletin related requests
*/
@Controller
@RequestMapping("/bulletin")
public class BulletinController{
protected static Logger logger = Logger.getLogger("controller");
@Resource(name="adminService")
private GenericService adminService;
@Resource(name="personalService")
private GenericService personalService;
@Resource(name="publicService")
private GenericService publicService;
/**
* Retrieves the View page.
* <p>
* This loads all authorized posts.
*/
@RequestMapping(value = "/view", method = RequestMethod.GET)
public ModelAndView getViewAllPage() {
logger.debug("Received request to view all page");
ModelAndView model = new ModelAndView("bulletinPage");
// Retrieve items from service and add to model
model.addObject("adminposts", adminService.getAll());
model.addObject("personalposts", personalService.getAll());
model.addObject("publicposts", publicService.getAll());
// Add our current role and username
model.addObject("role", SecurityContextHolder.getContext().getAuthentication().getAuthorities());
model.addObject("username", SecurityContextHolder.getContext().getAuthentication().getName());
// This will resolve to /WEB-INF/jsp/bulletinpage.jsp
return model;
}
}
B中。 AdminService.getAll方法。调用此方法时,它将返回所有管理员帖子。永远不会调用hasPermission方法。 (hasRole方法被调用并且正常工作。)
/**
* Service for processing Admin related posts.
*/
@Service("adminService")
@Transactional
public class AdminService implements GenericService {
protected static Logger logger = Logger.getLogger("service");
private Map<Long, Post> adminPosts;
private int nextId;
public void setDataSource(DataSource dataSource) {
initializeAllPosts();
}
private void initializeAllPosts() {
this.adminPosts = new HashMap<Long, Post>();
this.adminPosts.put(new Long(1), initializePost(new Long(1), new Date(), "Custom post #1 from admin"));
this.adminPosts.put(new Long(2), initializePost(new Long(2), new Date(), "Custom post #2 from admin"));
this.adminPosts.put(new Long(3), initializePost(new Long(3), new Date(), "Custom post #3 from admin"));
this.nextId = 4;
}
private AdminPost initializePost(Long id, Date date, String message) {
AdminPost adminPost = new AdminPost();
adminPost.setId(id);
adminPost.setDate(date);
adminPost.setMessage(message);
return adminPost;
}
@PostFilter("hasPermission(filterObject, 'READ')")
public List<Post> getAll() {
try {
logger.debug("Retrieving all admin posts");
if(null == this.adminPosts) initializeAllPosts();
List<Post> posts = new ArrayList<Post>();
for(Post adminPost : this.adminPosts.values()) {
posts.add(adminPost);
}
return posts;
} catch (Exception e) {
logger.error(e);
return null;
}
}
}
非常感谢任何帮助。谢谢。