Spring 4 MVC + Apache Shiro
Spring 4 MVC + Apache Shiro
我有一个 Spring 4 MVC 应用程序,它对所有端点使用 @RestController
注释。该应用程序不使用 web.xml
或 applicationContext.xml
文件。一切都运行良好,现在我正在尝试让 Apache Shiro 与其他一切协同工作。
我喜欢做的是在访问我构建的任何 REST 服务时出现 authc/authz 问题时让 Shiro 抛出异常。
到目前为止,我已经能够为初始化 Shiro 设置一个基本的 class 设置:
@Configuration
public class ShiroInitializer {
@Bean(name = "realmLocal")
@DependsOn ("lifecycleBeanPostProcessor")
public Realm realmLocal() {
return new AuthorizingRealm() {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
};
}
@Bean (name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public org.apache.shiro.mgt.SecurityManager getSecurityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realmLocal());
return securityManager;
}
@DependsOn("lifecycleBeanPostProcessor")
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
// enable shiro annotations
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(getSecurityManager());
return advisor;
}
@Bean (name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilter() {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(getSecurityManager());
Map<String, String> filters = new ConcurrentHashMap<>();
filters.put("/**", "authcBasic");
shiroFilter.setFilterChainDefinitionMap(filters);
return shiroFilter;
}
}
当我使用 @RequiresUser
构建这样的端点并在初始化程序的 AuthorizingRealm
中设置断点时,似乎没有任何结果并且消息显示时没有启动任何 authc/authz功能:
@RestController
@RequestMapping (value = "/")
@RequiresUser
public class RootEndpoint {
@RequestMapping (method = RequestMethod.GET)
public String doGet() throws Exception {
return "{ \"hello\": \"world\" }";
}
}
这是我的问题
- Q1 我的配置中缺少什么?请记住,我正在尽可能避免 XML 配置。
- Q2 有了基础之后,我可以用什么来抛出异常而不是将用户重定向到另一个页面?我需要自己定制
ShiroFilterFactoryBean
吗?
我能够通过实际切换到 Spring 引导来实现它,最近代码所有者允许我这样做。我最终为 Shiro 设置了一个配置 class,如下所示:
@Configuration
public class ShiroConfiguration {
@Bean
public ShiroFilterFactoryBean getShiroFilter() {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(getSecurityManager());
return factoryBean;
}
@Bean (name = "securityManager")
public DefaultWebSecurityManager getSecurityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getLocaleRealm());
securityManager.setSessionManager(getSessionManager());
return securityManager;
}
@Bean
public DefaultWebSessionManager getSessionManager() {
final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(43200000);
return sessionManager;
}
@Bean (name = "localRealm")
@DependsOn ("lifecycleBeanPostProcessor")
public LocalRealm getLocaleRealm() {
return new LocalRealm();
}
@Bean (name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public MethodInvokingFactoryBean getMethodInvokingFactoryBean() {
MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
factoryBean.setArguments(new Object[]{getSecurityManager()});
return factoryBean;
}
}
我还添加了一个自定义处理程序来使用异常和自定义 return 数据,方法是添加一个 @ControllerAdvice
实现,其中包含:
@ExceptionHandler ({
AuthenticationException.class,
UnknownAccountException.class,
UnauthenticatedException.class,
IncorrectCredentialsException.class,
UnauthorizedException.class}
)
@ResponseStatus (value = HttpStatus.UNAUTHORIZED)
@ResponseBody
public RestApiErrorResponse handleUnauthorized() {
return build(HttpStatus.UNAUTHORIZED);
}
我有一个 Spring 4 MVC 应用程序,它对所有端点使用 @RestController
注释。该应用程序不使用 web.xml
或 applicationContext.xml
文件。一切都运行良好,现在我正在尝试让 Apache Shiro 与其他一切协同工作。
我喜欢做的是在访问我构建的任何 REST 服务时出现 authc/authz 问题时让 Shiro 抛出异常。
到目前为止,我已经能够为初始化 Shiro 设置一个基本的 class 设置:
@Configuration
public class ShiroInitializer {
@Bean(name = "realmLocal")
@DependsOn ("lifecycleBeanPostProcessor")
public Realm realmLocal() {
return new AuthorizingRealm() {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
};
}
@Bean (name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public org.apache.shiro.mgt.SecurityManager getSecurityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realmLocal());
return securityManager;
}
@DependsOn("lifecycleBeanPostProcessor")
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
// enable shiro annotations
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(getSecurityManager());
return advisor;
}
@Bean (name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilter() {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(getSecurityManager());
Map<String, String> filters = new ConcurrentHashMap<>();
filters.put("/**", "authcBasic");
shiroFilter.setFilterChainDefinitionMap(filters);
return shiroFilter;
}
}
当我使用 @RequiresUser
构建这样的端点并在初始化程序的 AuthorizingRealm
中设置断点时,似乎没有任何结果并且消息显示时没有启动任何 authc/authz功能:
@RestController
@RequestMapping (value = "/")
@RequiresUser
public class RootEndpoint {
@RequestMapping (method = RequestMethod.GET)
public String doGet() throws Exception {
return "{ \"hello\": \"world\" }";
}
}
这是我的问题
- Q1 我的配置中缺少什么?请记住,我正在尽可能避免 XML 配置。
- Q2 有了基础之后,我可以用什么来抛出异常而不是将用户重定向到另一个页面?我需要自己定制
ShiroFilterFactoryBean
吗?
我能够通过实际切换到 Spring 引导来实现它,最近代码所有者允许我这样做。我最终为 Shiro 设置了一个配置 class,如下所示:
@Configuration
public class ShiroConfiguration {
@Bean
public ShiroFilterFactoryBean getShiroFilter() {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(getSecurityManager());
return factoryBean;
}
@Bean (name = "securityManager")
public DefaultWebSecurityManager getSecurityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getLocaleRealm());
securityManager.setSessionManager(getSessionManager());
return securityManager;
}
@Bean
public DefaultWebSessionManager getSessionManager() {
final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(43200000);
return sessionManager;
}
@Bean (name = "localRealm")
@DependsOn ("lifecycleBeanPostProcessor")
public LocalRealm getLocaleRealm() {
return new LocalRealm();
}
@Bean (name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public MethodInvokingFactoryBean getMethodInvokingFactoryBean() {
MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
factoryBean.setArguments(new Object[]{getSecurityManager()});
return factoryBean;
}
}
我还添加了一个自定义处理程序来使用异常和自定义 return 数据,方法是添加一个 @ControllerAdvice
实现,其中包含:
@ExceptionHandler ({
AuthenticationException.class,
UnknownAccountException.class,
UnauthenticatedException.class,
IncorrectCredentialsException.class,
UnauthorizedException.class}
)
@ResponseStatus (value = HttpStatus.UNAUTHORIZED)
@ResponseBody
public RestApiErrorResponse handleUnauthorized() {
return build(HttpStatus.UNAUTHORIZED);
}