spring shiro框架的学习记录1

一、shiro的出处:

        官方网站:http://shiro.apache.org

        相关参考博文:

  • http://my.oschina.net/u/866794/blog/107756


  • http://www.ibm.com/developerworks/cn/java/j-lo-shiro/
  • http://hpuzhuhai.iteye.com/blog/1956046


二、maven的配置内容:

我的配置内容如下:

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.2.2</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-web</artifactId>
  <version>1.2.2</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-aspectj</artifactId>
  <version>1.2.2</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.2.2</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-ehcache</artifactId>
  <version>1.2.2</version>
</dependency>

上面的jar思路很清晰,除了shiro-code.jar外,与什么框架结合,就加上什么样jar。

具体全部的maven配置文件可参考:http://shiro.apache.org/download.html

三、spring项目如何集成shiro框架-简单示例

    1.web.xml:

<!--配置过滤器让请求资源经过 Shiro 的过滤处理-->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

    2.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:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-3.2.xsd 
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"
	default-lazy-init="false">


        <!-- 权限管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="shiroDbRealm" />
	</bean>
        <!--内部过滤器配置-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"
		depends-on="frameperms">
		<!-- shiro的核心安全接口 -->
		<property name="securityManager" ref="securityManager" />
		<!-- 要求登录时的链接 -->
		<property name="loginUrl" value="/login" />
		<!-- 登陆成功后要跳转的连接 -->
		<property name="successUrl" value="/index" />
		 <!-- 未授权时要跳转的连接 -->
		<property name="unauthorizedUrl" value="/unauth" />
 		<!-- shiro连接约束配置 -->
		<property name="filterChainDefinitions">
			<value>
			  <!--静态资源直接通过-->  
			    /js/** = anon
			   /css/** = anon
			   /images/** = anon
			   /unauth = anon
			   /getCaptcha=anon
			   /login = anon
			   /favicon.ico = anon
			   <!--必须存在用户-->
			   /index = user
			   /logout = logout
			    <!--必须存在用户-->
			   /menu/leftMenu=user
			   <!--必须存在用户-->
			    /**/ajax/** = user 
			   <!--必须存在用户,所有的请求都要通过 frameperms 验证-->  
			   /** = user,frameperms
			</value>
		</property>
		<property name="filters">
			<map>
				<entry key="frameperms" value-ref="frameperms"></entry>
			</map>
		</property>
	</bean>         <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>
其中shiroDbRealm为认证授权类。具体代码如下:


/**
 * 关于shiro的缓存,我在这里说下.<br/>
 * 可以禁用shiro的缓存,调用spring的缓存,这样就省去了缓存的整合.<br/>
 * 其他框架遇到缓存问题,同样的思路解决.
 * @author 9iu.org
 *
 */
//认证数据库存储
@Component("shiroDbRealm")
public class ShiroDbRealm extends AuthorizingRealm {
	public Logger logger = Logger.getLogger(getClass());
	@Resource
	IUserRoleMenuService userRoleMenuService;
	public static final String HASH_ALGORITHM = "MD5";
	public static final int HASH_INTERATIONS = 1;
	private static final int SALT_SIZE = 8;
	public ShiroDbRealm() {
		// super.setAuthenticationCacheName(authenticationCacheName);

	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principalCollection) {

		ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal();
		// String userId = (String)
		// principalCollection.fromRealm(getName()).iterator().next();
		String userId = shiroUser.getId();
		if(StringUtils.isBlank(userId)){
			return null;
		}
		// 添加角色及权限信息
		SimpleAuthorizationInfo sazi = new SimpleAuthorizationInfo();
		try {
			sazi.addRoles(userRoleMenuService.getRolesAsString(userId));
			sazi.addStringPermissions(userRoleMenuService.getPermissionsAsString(userId));
		} catch (Exception e) {
			logger.error(e);
		}
	
		
		return sazi;
	}

	// 认证
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		/*
		String pwd = new String(upToken.getPassword());
		if (StringUtils.isNotBlank(pwd)) {
			pwd = DigestUtils.md5Hex(pwd);
		}
*/
		// 调用业务方法
		User user = null;
		try {
			user = userRoleMenuService.findLoginUser(upToken.getUsername(), new String(upToken.getPassword()));
		} catch (Exception e) {
			logger.error(e);
		}

		if (user != null) {
			// 要放在作用域中的东西,请在这里进行操作
			// SecurityUtils.getSubject().getSession().setAttribute("c_user",
			// user);
			// byte[] salt = EncodeUtils.decodeHex(user.getSalt());
			return new SimpleAuthenticationInfo(new ShiroUser(user),user.getPassword(),getName());
		}
		// 认证没有通过
		return null;
	}
	/**
	 * 设定Password校验的Hash算法与迭代次数.
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(HASH_ALGORITHM);
		matcher.setHashIterations(HASH_INTERATIONS);

		setCredentialsMatcher(matcher);
	}

配置文件中frameperms类,内容如下:

@Component("frameperms")
public class FramePermissionsAuthorizationFilter extends	PermissionsAuthorizationFilter {
	public Logger logger=Logger.getLogger(getClass());
	@Resource
	private IMenuService menuService;
	
	@Override
	public boolean isAccessAllowed(ServletRequest request,
			ServletResponse response, Object mappedValue) throws IOException {
		HttpServletRequest req = (HttpServletRequest) request;
		Subject subject = getSubject(request, response);
		String uri = req.getRequestURI();
		String requestURL = req.getRequestURL().toString();
		String contextPath = req.getContextPath();
		if(uri.endsWith("/pre")){// 去掉pre
			uri=uri.substring(0,uri.length()-4);
		}
		int i=uri.indexOf(contextPath);
		if(i>-1){
			uri=uri.substring(i+contextPath.length());
		}
		if(StringUtils.isBlank(uri)){
			uri="/";
		}
		 boolean permitted = subject.isPermitted(uri);
		 String isqx="否";
		 if(permitted){
			 isqx="是";
		 }
		 String ip = IPUtils.getClientAddress(req);
		
		 Fwlog fwlog=new Fwlog();
		 fwlog.setFwUrl(requestURL);
		 fwlog.setIsqx(isqx);
		 fwlog.setIp(ip);
			Subject user = SecurityUtils.getSubject();
		 ShiroUser shiroUser = (ShiroUser) user.getPrincipals().getPrimaryPrincipal();
		fwlog.setUserCode(shiroUser.getAccount());
		fwlog.setUserName(shiroUser.getName());
		Date startDate=new Date();
		fwlog.setStartDate(startDate);
		fwlog.setStrDate(DateUtils.convertDate2String("yyyy-MM-dd HH:mm:ss.SSSS", startDate));
		HttpSession httpSession = req.getSession(false);
		if(httpSession!=null){
			fwlog.setSessionId(httpSession.getId());
		}
		try {
			String menuName = menuService.getNameByPageurl(uri);
			fwlog.setMenuName(menuName);
			menuService.save(fwlog);
		} catch (Exception e) {
			logger.error(e);
		}
		return permitted;

	}
	
}



登录时的代码如下:


@RequestMapping(value = "/login",method=RequestMethod.POST)
	public String loginPost(User currUser,HttpSession session,Model model,HttpServletRequest request) throws Exception {
		Subject user = SecurityUtils.getSubject();
		  String code = (String) session.getAttribute(GlobalStatic.DEFAULT_CAPTCHA_PARAM);
		  if(StringUtils.isNotBlank(code)){
			  code=code.toLowerCase().toString();
		  }
		String submitCode = WebUtils.getCleanParam(request, GlobalStatic.DEFAULT_CAPTCHA_PARAM);
		  if(StringUtils.isNotBlank(submitCode)){
			  submitCode=submitCode.toLowerCase().toString();
		  }
		if (StringUtils.isBlank(submitCode) ||StringUtils.isBlank(code)||!code.equals(submitCode)) {
			model.addAttribute("message", "验证码错误!");
			return "/login";
        }
		
		UsernamePasswordToken token = new UsernamePasswordToken(currUser.getAccount(),currUser.getPassword());
		
		token.setRememberMe(true);
		try{
		user.login(token);
	}catch(IncorrectCredentialsException e){
		model.addAttribute("message", "账号或密码错误");
		return "/login";
	}catch(Exception e){
		model.addAttribute("message", "账号或密码错误");
		return "/login";
	}
		
		return "redirect:/index";
	}

四、代码讲解

  1. 根据shiro内部配置,shiro来选择进入哪个环节,是直接进入controller,还是验证阶段等。
  2. 用户提交登录表单,进入controller层,进入上述登录代码进行验证。
  3. 但代码执行user.login(token);句时,会进入shiro的认证模块中,为ShiroDbRealm类的doGetAuthenticationInfo认证方法,认证通过后,返回SimpleAuthenticationInfo对象实例
  4. 当用户每次访问菜单时,先进入ShiroDbRealmdoGetAuthorizationInfo授权方法,对当前用户进行授权,
  5. 然后根据shiro内部配置时,会进入验证阶段FramePermissionsAuthorizationFilter。进行验证。






你可能感兴趣的:(shiro)