shiro与spring整合详解与spring项目中shiro注解不生效的解决办法

一、spring项目中的shiro配置

(1)web.xml配置


	
		shiroFilter
		org.springframework.web.filter.DelegatingFilterProxy
		
			targetFilterLifecycle
			true
		
	
	
		shiroFilter
		/*
	

(2)shiro与spring整合配置


	
	
	
		
	

	
	

	
	   
	
	
		
        
	
	
	
		
	
	
	
		
		
		
		
		
		
		
		
		
			
			
			
			
				/static/** = anon
				/login/** = anon
				/common/** = anon
				/admin/** = authc,roles[admin]
				/* = authc
				/** = authc
			
		
	
	
	

二、realm和自定义密码校验器实现

1、realm实现

public class MyRealm extends AuthorizingRealm{
	Logger log=Logger.getLogger(MyRealm.class);
	
	@Autowired
    private UserService userService;//这是自己实现的用户信息操作类,实现用户信息,用户角色信息、用户权限信息查询功能

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		UserInfo user = (UserInfo) principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 查询角色信息
		Collection roles = userService.findRoles(user);
		info.addRoles(roles);
		log.info("shiro获取用户所属角色列表:"+roles);
		// 查询权限信息
		Collection permissions = userService.findPermissions(user.getSystemuserid());
		info.addStringPermissions(permissions);
		log.info("shiro获取用户权限列表:"+permissions);
		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException{
		//用户输入的用户名密码
		String loginname=  token.getPrincipal().toString();
		Object password=token.getCredentials();
		log.info("shiro正在处理尝试登录的用户信息:"+loginname+",密码:"+new String((char[])password));
		//数据库中的用户信息
		UserInfo user =userService.queryUserInfoByLoginName(loginname);
		if(user==null||CommonUtil.isNull(user.getLoginusername(),user.getPassword(),user.getSystemuserid())){
			return null;
		}
		log.info("shiro获取到当前用户尝试登录的真实数据:"+user.getLoginusername()+",密码:"+user.getPassword());
		//数据库中的正确的账户信息
		AuthenticationInfo accountInfo =new SimpleAuthenticationInfo(user, user.getPassword(),getName());
				
		//自己获取密码验证器(由于shiro实现的密码校验方法是密码错误会直接抛异常,不采用,所以改成直接手动校验)
		CredentialsMatcher matcher=getCredentialsMatcher();
		if(matcher==null){
			log.error("没有配置密码匹配器");
			return null;
		}
		//校验密码
		if(matcher.doCredentialsMatch(token,accountInfo)){
			return accountInfo;//校验通过,返回账号信息
		}
		
		return null;
	}


}

2、自定义密码校验器


/**
 * 自定义shiro密码匹配(密码是在md5散列值的基础上再次进行md5加盐操作,加盐值不保存在数据库,而是放在配置文件中)
 * @author eguid
 *
 */
public class MyCredentialsMatcher extends CodecSupport implements CredentialsMatcher {
	private static final Logger log = LoggerFactory.getLogger(MyCredentialsMatcher.class);

	protected Object getCredentials(AuthenticationToken token) {
		return token.getCredentials();
	}

	protected Object getCredentials(AuthenticationInfo info) {
		return info.getCredentials();
	}

	@Autowired
	private CommonConfigs commonConfigs;
	/**
	 * 验证密码
	 * 
	 * @param tokenCredentials
	 * @param accountCredentials
	 * @return
	 */
	protected boolean equals(Object tokenCredentials, Object accountCredentials) {
		if (log.isDebugEnabled()) {
			log.debug("Performing credentials equality check for tokenCredentials of type ["
					+ tokenCredentials.getClass().getName() + " and accountCredentials of type ["
					+ accountCredentials.getClass().getName() + "]");
		}
		if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) {
			if (log.isDebugEnabled()) {
				log.debug("Both credentials arguments can be easily converted to byte arrays.  Performing "
						+ "array equals comparison");
			}
			byte[] tokenBytes = toBytes(tokenCredentials);
			byte[] accountBytes = toBytes(accountCredentials);
			return MessageDigest.isEqual(tokenBytes, accountBytes);
		} else {
			return accountCredentials.equals(tokenCredentials);
		}
	}
	
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		Object tokenCredentials = getCredentials(token);
		Object accountCredentials = getCredentials(info);
		String account=String.valueOf((char[])tokenCredentials);
		if(commonConfigs.getMd5salt()==null){
			if (log.isDebugEnabled()) {
				log.debug("配置文件中的加盐值为空,无法进行密码匹配,请确认配置文件是否在指定位置或配置指定加盐值");
			}
			return false;
		}
		String saltaccount=MD5Util.getMD5(account, commonConfigs.getMd5salt());
		if (log.isDebugEnabled()) {
			log.debug("加盐后的密码:"+saltaccount);
		}
		return equals(accountCredentials, saltaccount.toCharArray());
	}

}

三、注解使用及模板标签使用(其中注解无效)

1、注解使用

@RequiresPermissions({"user:update:view"})//检查操作权限

@RequiresPermissions(value={"user:add","user:view"},logical=Logical.OR)//两个操作权限其中一个满足条件即可通过检查

@RequiresRoles({"admin"})//检查角色

@RequiresRoles(value={"debug","admin"},logical=Logical.OR)//两个角色其中一个角色满足条件即可


@RequiresAuthentication//检查是否通过shiro认证
@RequiresGuest//不需要验证
@RequiresUser//检查用户是否是当前系统中的用户


2、标签使用

使用标签需要先导入shiro的标签库<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

(1)显示用户身份信息


默认调用Subject.getPrincipal()获取



相当于((User)Subject.getPrincipals()).getUsername()


(2)已登录shiro用户显示

   
欢迎[]登录,退出  

(3)匿名用户访问

未经过shiro验证的用户(游客,匿名用户)  


(4)已经在shiro登录过的(已登录用户)

   
    用户[]已身份验证通过  
 

(5)没有在shiro登录过的

 
    未身份验证(包括记住我)

(6)检查角色

 
    用户[]拥有角色admin


检查任意角色(其中一个满足条件即通过,相当于OR)
 
    用户[]拥有角色admin或user


不具有角色(反向判断)
 
    用户[]不具有角色abc


(7)操作权限判断

   
    用户[]拥有权限user:create
  
    

不具有操作权限(反向判断)
   
    用户[]没有权限org:create
  
  



四、注解不生效解决办法

把shiro注解放到springMVC的注解扫描之后(即放在springMVC容器中加载)


	
	
	
		
	
把上面的shiro直接扫描放到下面的servlet-context.xml中即可让shiro注解生效


	
		appServlet
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			/WEB-INF/spring/servlet-context.xml
		
		2
	
	
		appServlet
		/
	






你可能感兴趣的:(shiro)