spring整合shiro
配置一个存储权限的缓存 ehcache-shiro.xml
<ehcache updateCheck="false" name="shiroCache"> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /> </ehcache>
整合spring配置 applicationContext-shiro.xml
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <description>Shiro的配置</description> <!-- SecurityManager配置 --> <!-- 配置Realm域 --> <!-- 密码比较器 --> <!-- 代理如何生成? 用工厂来生成Shiro的相关过滤器--> <!-- 配置缓存:ehcache缓存 --> <!-- 安全管理 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- Single realm app. If you have multiple realms, use the 'realms' property instead. --> <property name="realm" ref="authRealm"/><!-- 引用自定义的realm --> <!-- 二级缓存 --> <property name="cacheManager" ref="shiroEhcacheManager"/> </bean> <!-- 自定义权限认证 --> <bean id="authRealm" class="com.xwer.jk.shiro.AuthorRealm"> <property name="userService" ref="userService"/> <!-- 自定义密码加密算法 密码比较器 --> <property name="credentialsMatcher" ref="passwordMatcher"/> </bean> <!-- 设置密码加密策略自定义的密码比较器 md5hash --> <bean id="passwordMatcher" class="com.xwer.jk.shiro.CustomerCrednetialsMatcher"/> <!-- filter-name这个名字的值来自于web.xml中filter的名字 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!--登录页面 --> <property name="loginUrl" value="/index.jsp"></property> <!-- 登录成功后 --> <property name="successUrl" value="/home.action"></property> <property name="filterChainDefinitions"> <!-- /**代表下面的多级目录也过滤 --> <value> /index.jsp* = anon /home* = anon /sysadmin/login/login.jsp* = anon /sysadmin/login/logout.jsp* = anon /login* = anon /logout* = anon /components/** = anon /css/** = anon /images/** = anon /js/** = anon /make/** = anon /skin/** = anon /stat/** = anon /ufiles/** = anon /validator/** = anon /resource/** = anon /** = authc /*.* = authc </value> </property> </bean> <!-- 用户授权/认证信息Cache, 采用EhCache缓存 下面不用多配置 --> <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 生成代理,通过代理进行控制 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <!-- 安全管理器 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>
自定义比较器类
/** * 自定义密码比较器 * @author Administrator * */ public class CustomerCrednetialsMatcher extends SimpleCredentialsMatcher{ //重写父类方法, token 表示用户在页面输入的用户名和密码,info 表示从数据库取出的数据 @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { //1.向下转型 UsernamePasswordToken upToken = (UsernamePasswordToken) token; //2.将用户 在界面输入的原始加密 进行md5 hash加密 ------- 直接使用toString 获取的是char[] 的地址 //String pwd = Encrypt.md5(upToken.getPassword().toString(), upToken.getUsername()); String pwd = Encrypt.md5(new String(upToken.getPassword()), upToken.getUsername()); //3.从数据库取出加密的密码 Object dbPwd = info.getCredentials(); return this.equals(pwd, dbPwd); } }
Encrypt 类
public class Encrypt { /* * 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据, * 常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”, * 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”, * 可以到一些md5解密网站很容易的通过散列值得到密码“admin”, * 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据, * 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。 */ //高强度加密算法,不可逆 /** * 默认加密方式 * @param password 用户密码 * @param salt 用户名 * @return */ public static String md5(String password, String salt){ return new Md5Hash(password,salt,2).toString(); } public static void main(String[] args) { System.out.println(new Md5Hash("admin","admin",2).toString()); } }
shiro 核心认证授权 AuthorRealm.java
public class AuthorRealm extends AuthorizingRealm{ private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } //授权 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获取当前用户,先根据realm的名字去获取相应的realm User user = (User)principals.fromRealm(this.getName()).iterator().next(); logger.info("用户 {} 授权中.....",user.getUserName()); //得到权限字符串 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //获取用户的权限 Set<Role> roles = user.getRoles();//对象导航,关联级别数据加载,得到当前用户的所有角色 List<String> list = new ArrayList<String>(); for(Role role :roles){ //对象导航,关联级别数据加载,得到每个角色下的模块列表 Set<Module> modules = role.getModules(); for(Module m:modules){ if(m.getCtype()==0){ //说明是主菜单,组织权限字符串 list.add(m.getCpermission()); } } } info.addStringPermissions(list); return info; } //认证 登录 protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken)token; logger.info("用户 {} 认证中.....",new String(upToken.getUsername())); // String hql = "from User where userName = ?"; //User user = userService.findUserByName(upToken.getUsername()); List<User> list = userService.find(hql, User.class, new String[]{upToken.getUsername()}); if(list!=null&& list.size()>0){ User user = list.get(0); //当前用户,用户密码 AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName()); return info; //此处如果返回,就会立即 进入密码比较器 } return null; } }