Shiro权限框架
开发系统中,少不了权限,目前java里的权限框架有SpringSecurity和Shiro(以前叫做jsecurity),对于SpringSecurity:功能太过强大以至于功能比较分散,使用起来也比较复杂,跟Spring结合的比较好。对于初学Spring Security者来说,曲线还是较大,需要深入学习其源码和框架,配置起来也需要费比较大的力气,扩展性也不是特别强。
对于新秀Shiro来说,好评还是比较多的,使用起来比较简单,功能也足够强大,扩展性也较好。听说连Spring的官方都不用Spring Security,用的是Shiro,足见Shiro的优秀。
网上找到两篇介绍:
http://www.infoq.com/cn/articles/apache-shiro
http://www.ibm.com/developerworks/cn/opensource/os-cn-shiro/,
使用和配置起来还是比较简单。下面只是简单介绍下我们是如何配置和使用Shiro的(暂时只用到了Shiro的一部分,没有配置shiro.ini文件)。
首先是添加过滤器,在web.xml中:
1<filter> 2 <filter-name>shiroFilter</filter-name> 3 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 4 <init-param> 5 <param-name>targetFilterLifecycle</param-name> 6 <param-value>true</param-value> 7 </init-param> 8</filter> 9<filter-mapping> 10 <filter-name>shiroFilter</filter-name> 11 <url-pattern>/*</url-pattern> 12</filter-mapping>
权限的认证类:
1public class ShiroDbRealm extends AuthorizingRealm { 2 @Inject 3 private UserService userService ; 4 5 /** 6 * 认证回调函数,登录时调用. 7 */ 8 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) 9 throws AuthenticationException { 10 UsernamePasswordToken token = (UsernamePasswordToken) authcToken; 11 User user= userService.getUserByUserId(token.getUsername()); 12 if (user!= null) { 13 return new SimpleAuthenticationInfo(user.getUserName() 14 ,user.getPassWord() 15 ,getName()); 16 } else { 17 return null; 18 } 19 } 20 /** 21 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用. 22 */ 23 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 24 String loginName = (String) principals.fromRealm(getName()).iterator().next(); 25 User user= userService.getUserByUserId(loginName); 26 if (user != null) { 27 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 28 info.addStringPermission("common-user"); 29 return info; 30 } else { 31 return null; 32 } 33 } 34}
Spring的配置文件:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans > 3 <description>Shiro Configuration</description> 4 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/> 5 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 6 <property name="realm" ref="shiroDbRealm" /> 7 </bean> 8 <bean id="shiroDbRealm" class="com.company.service.common.shiro.ShiroDbRealm" /> 9 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 10 <property name="securityManager" ref="securityManager"/> 11 <property name="loginUrl" value="/common/security/login" /> 12 <property name="successUrl" value="/common/security/welcome" /> 13 <property name="unauthorizedUrl" value="/common/security/unauthorized"/> 14 <property name="filterChainDefinitions"> 15 <value> 16 /resources/** = anon 17 /manageUsers = perms[user:manage] 18 </value> 19 </property> 20 </bean> 21 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> 22 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> 23 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> 24 <property name="securityManager" ref="securityManager"/> 25 </bean> 26</beans>
登录的Controller:
1@Controller 2@RequestMapping(value = "/common/security/*") 3public class SecurityController { 4 @Inject 5 private UserService userService; 6 @RequestMapping(value = "/login") 7 public String login(String loginName, String password, 8 HttpServletResponse response, 9 HttpServletRequest request) throws Exception { 10 User user = userService.getUserByLogin(loginName); 11 if (null != user) { 12 setLogin(loginInfoVO.getuserName(), loginInfoVO.getUserId()); 13 return "redirect:/common/security/welcome"; 14 } else { 15 return "redirect:/common/path?path=showLogin"; 16 } 17 }; 18 public static final void setLogin(String userName, String password) { 19 Subject currentUser = SecurityUtils.getSubject(); 20 if (!currentUser.isAuthenticated()) { 21 //collect user principals and credentials in a gui specific manner 22 //such as username/password html form, X509 certificate, OpenID, etc. 23 //We'll use the username/password example here since it is the most common. 24 //(do you know what movie this is from? ;) 25 UsernamePasswordToken token = new UsernamePasswordToken(userName, password); 26 //this is all you have to do to support 'remember me' (no config - built in!): 27 token.setRememberMe(true); 28 currentUser.login(token); 29 } 30 }; 31 32 @RequestMapping(value="/logout") 33 @ResponseBody 34 public void logout(HttpServletRequest request){ 35 Subject subject = SecurityUtils.getSubject(); 36 if (subject != null) { 37 subject.logout(); 38 } 39 request.getSession().invalidate(); 40 }; 41}
注册和获取当前登录用户:
1public static final void setCurrentUser(User user) { 2 Subject currentUser = SecurityUtils.getSubject(); 3 if (null != currentUser) { 4 Session session = currentUser.getSession(); 5 if (null != session) { 6 session.setAttribute(Constants.CURRENT_USER, user); 7 } 8 } 9 } 10public static final User getCurrentUser() { 11 Subject currentUser = SecurityUtils.getSubject(); 12 if (null != currentUser) { 13 Session session = currentUser.getSession(); 14 if (null != session) { 15 User user = (User) session.getAttribute(Constants.CURRENT_USER); 16 if(null != user){ 17 return user; 18 } 19 } 20 } 21} 22/** 23 * 清除所有用户授权信息缓存. 24 */ 25public void clearAllCachedAuthorizationInfo() { 26 Cache<Object, AuthorizationInfo> cache = getAuthorizationCache(); 27 if (cache != null) { 28 for (Object key : cache.keys()) { 29 cache.remove(key); 30 } 31 } 32}
需要的jar包有3个:shiro-core.jar,shiro-spring.jar,shiro-web.jar。感觉shiro用起来比SpringSecurity简单很多。