Spring 4 - 带有服务的自定义 SecurityExpression
Spring 4 - Custom SecurityExpression with Service
在我的一个控制器中,我需要使用比角色更细粒度的方法来保护方法。
我创建了一个 MethodSecurityExpressionHandler
,但我不知道如何访问其中的一个 @Services
。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class CustomMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler();
handler.setApplicationContext(applicationContext);
return super.createExpressionHandler();
}
@Bean
public MethodSecurityExpressionHandler expressionHandler() {
return new CustomMethodSecurityExpressionHandler();
}
}
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private Object target;
//**This is what I need to work**
@Autowired
private RepositoryService repositoryService;
public boolean canViewFolder(String uuid){
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return repositoryService.checkFolderPermissions(currentUser.getUsername(), uuid);
}
public CustomMethodSecurityExpressionRoot(Authentication a) {
super(a);
}
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
public Object getFilterObject() {
return filterObject;
}
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
public Object getReturnObject() {
return returnObject;
}
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
}
在 CustomMethodSecurityExpressionRoot
中为您的 RepositoryService 创建一个 setter
覆盖 CustomMethodSecurityExpressionHandler 中的 setApplicationContext 以使您传入的 applicationContext 处于可访问级别。
在使用 applicationContext 的 createSecurityExpressionRoot 中,从您的上下文中传入 RepositoryService bean。代码如下。另请注意我对 createExpressionHandler() 和 expressionHandler() 所做的更改。在 create ExpressionHandler 中,您调用的是仅使用默认实现的 super,而不是您之前两行刚刚更新的对象。在 expressionHandler() 中,您正在创建 CustomMethodSecurityExpressionHandler() 的新实例,而不是检索您在 createExpressionHandler() 中创建的实例。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class CustomMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler();
handler.setApplicationContext(applicationContext);
return handler;
}
@Bean
public MethodSecurityExpressionHandler expressionHandler() {
return createExpressionHandler();
}
}
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
root.setRepositoryService(applicationContext.getBean(RepositoryService.class);
return root;
}
@Override
protected void setApplicationContext(applicationContext){
super.setApplicationContext(applicationContext);
this.applicationContext = applicationContext;
}
}
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private Object target;
private RepositoryService repositoryService;
public boolean canViewFolder(String uuid){
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return repositoryService.checkFolderPermissions(currentUser.getUsername(), uuid);
}
public CustomMethodSecurityExpressionRoot(Authentication a) {
super(a);
}
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
public Object getFilterObject() {
return filterObject;
}
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
public Object getReturnObject() {
return returnObject;
}
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
public void setRepositoryService(RepositoryService repositoryService){
this.repositoryService = repositoryService;
}
}
已接受的答案在最新版本的 Spring/Spring 安全性中不再有效。尝试进行配置 class ApplicationContextAware 将使您能够访问 ApplicationContext,但您的 CustomMethodSecurityExpressionHAndler 将被忽略。
而是通过覆盖 getBeanFactory 方法更新您的配置 class 以获取 BeanFactory。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class CustomMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
private BeanFactory beanFactory
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler();
handler.setBeanFactory(beanFactory);
return handler;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
super.setBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
}
然后您可以在您的 CustomMethodSecurityExpressionHandler
中查找您需要的 beans
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private BeanFactory beanFactory;
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
root.setRepositoryService(beanFactory.getBean(RepositoryService.class);
return root;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
在我的一个控制器中,我需要使用比角色更细粒度的方法来保护方法。
我创建了一个 MethodSecurityExpressionHandler
,但我不知道如何访问其中的一个 @Services
。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class CustomMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler();
handler.setApplicationContext(applicationContext);
return super.createExpressionHandler();
}
@Bean
public MethodSecurityExpressionHandler expressionHandler() {
return new CustomMethodSecurityExpressionHandler();
}
}
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private Object target;
//**This is what I need to work**
@Autowired
private RepositoryService repositoryService;
public boolean canViewFolder(String uuid){
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return repositoryService.checkFolderPermissions(currentUser.getUsername(), uuid);
}
public CustomMethodSecurityExpressionRoot(Authentication a) {
super(a);
}
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
public Object getFilterObject() {
return filterObject;
}
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
public Object getReturnObject() {
return returnObject;
}
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
}
在 CustomMethodSecurityExpressionRoot
中为您的 RepositoryService 创建一个 setter覆盖 CustomMethodSecurityExpressionHandler 中的 setApplicationContext 以使您传入的 applicationContext 处于可访问级别。
在使用 applicationContext 的 createSecurityExpressionRoot 中,从您的上下文中传入 RepositoryService bean。代码如下。另请注意我对 createExpressionHandler() 和 expressionHandler() 所做的更改。在 create ExpressionHandler 中,您调用的是仅使用默认实现的 super,而不是您之前两行刚刚更新的对象。在 expressionHandler() 中,您正在创建 CustomMethodSecurityExpressionHandler() 的新实例,而不是检索您在 createExpressionHandler() 中创建的实例。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class CustomMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler();
handler.setApplicationContext(applicationContext);
return handler;
}
@Bean
public MethodSecurityExpressionHandler expressionHandler() {
return createExpressionHandler();
}
}
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
root.setRepositoryService(applicationContext.getBean(RepositoryService.class);
return root;
}
@Override
protected void setApplicationContext(applicationContext){
super.setApplicationContext(applicationContext);
this.applicationContext = applicationContext;
}
}
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private Object target;
private RepositoryService repositoryService;
public boolean canViewFolder(String uuid){
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return repositoryService.checkFolderPermissions(currentUser.getUsername(), uuid);
}
public CustomMethodSecurityExpressionRoot(Authentication a) {
super(a);
}
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
public Object getFilterObject() {
return filterObject;
}
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
public Object getReturnObject() {
return returnObject;
}
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
public void setRepositoryService(RepositoryService repositoryService){
this.repositoryService = repositoryService;
}
}
已接受的答案在最新版本的 Spring/Spring 安全性中不再有效。尝试进行配置 class ApplicationContextAware 将使您能够访问 ApplicationContext,但您的 CustomMethodSecurityExpressionHAndler 将被忽略。
而是通过覆盖 getBeanFactory 方法更新您的配置 class 以获取 BeanFactory。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class CustomMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
private BeanFactory beanFactory
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler();
handler.setBeanFactory(beanFactory);
return handler;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
super.setBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
}
然后您可以在您的 CustomMethodSecurityExpressionHandler
中查找您需要的 beanspublic class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private BeanFactory beanFactory;
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
root.setRepositoryService(beanFactory.getBean(RepositoryService.class);
return root;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}