Shiro与Spring、Springmvc的整合

1、在web.xml中配置Shiro的filter

在web系统中,shiro也通过filter进行拦截。filter拦截后将操作权交给spring中配置的filterChain(过虑链儿)
shiro提供很多filter。

<!-- shiro的filter -->
<!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
<filter>
	<filter-name>shiroFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	<!-- 设置true由servlet容器控制filter的生命周期 -->
	<init-param>
		<param-name>targetFilterLifecycle</param-name>
		<param-value>true</param-value>
	</init-param>
	<!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean-->
	<init-param>
		<param-name>targetBeanName</param-name>
		<param-value>shiroFilter</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>shiroFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

2、在applicationContext-shiro.xml 中配置web.xml中fitler对应spring容器中的bean。##

<!-- web.xml中shiro的filter对应的bean -->
<!-- Shiro 的Web过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
		<property name="loginUrl" value="/login.action" />
		<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
		<property name="successUrl" value="/first.action"/>
		<!-- 通过unauthorizedUrl指定没有权限操作时跳转页面-->
		<property name="unauthorizedUrl" value="/refuse.jsp" />
		<!-- 自定义filter配置 -->
		<property name="filters">
			<map>
				<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中-->
				<entry key="authc" value-ref="formAuthenticationFilter" />
			</map>
		</property>
		
		<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
		<property name="filterChainDefinitions">
			<value>
			</value>
		</property>
	</bean>

<!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customRealm" />	
	</bean>

<!-- realm -->
<bean id="customRealm" class="cn.itcast.ssm.shiro.CustomRealm">
	<!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
	<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>

3、配置静态资源的匿名访问

<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
		<property name="filterChainDefinitions">
			<value>
<!-- 对静态资源设置匿名访问 -->
			/images/** = anon
			/js/** = anon
			/styles/** = anon
			</value>
		</property>

4、登录认证的实现

一、原理

使用FormAuthenticationFilter过虑器实现 ,原理如下:


 将用户没有认证时,请求loginurl进行认证,用户身份和用户密码提交数据到loginurl

 FormAuthenticationFilter拦截住取出request中的username和password(两个参数名称是可以配置的)

 FormAuthenticationFilter调用realm传入一个token(username和password)

 realm认证时根据username查询用户信息(在Activeuser中存储,包括 userid、usercode、username、menus)。

 如果查询不到,realm返回null,FormAuthenticationFilter向request域中填充一个参数(记录了异常信息)

二、代码实现

//登陆提交地址,和applicationContext-shiro.xml中配置的loginurl一致
	@RequestMapping("login")
	public String login(HttpServletRequest request)throws Exception{
		
		//如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
		String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
		//根据shiro返回的异常类路径判断,抛出指定异常信息
		if(exceptionClassName!=null){
			if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
				//最终会抛给异常处理器
				throw new CustomException("账号不存在");
			} else if (IncorrectCredentialsException.class.getName().equals(
					exceptionClassName)) {
				throw new CustomException("用户名/密码错误");
			} else if("randomCodeError".equals(exceptionClassName)){
				throw new CustomException("验证码错误 ");
			}else {
				throw new Exception();//最终在异常处理器生成未知错误
			}
		}
		//此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
		//登陆失败还到login页面
		return "login";
	}	

三、配置登录的拦截器

<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
	<property name="filterChainDefinitions">
		<value>
			<!-- 对静态资源设置匿名访问 -->
			/images/** = anon
			/js/** = anon
			/styles/** = anon
			<!-- /** = authc 所有url都必须认证通过才可以访问-->
			/** = authc
			<!-- /** = anon所有url都可以匿名访问 -->
			
		</value>

四、退出

不用我们去实现退出,只要去访问一个退出的url(该 url是可以不存在),由LogoutFilter拦截住,清除session。

在applicationContext-shiro.xml配置LogoutFilter

<property name="filterChainDefinitions">
		<value>
			<!-- 对静态资源设置匿名访问 -->
			/images/** = anon
			/js/** = anon
			/styles/** = anon
			<!-- /** = authc 所有url都必须认证通过才可以访问-->
			/** = authc
			<!-- /** = anon所有url都可以匿名访问 -->
			<!-- 请求 logout.action地址,shiro去清除session-->
			/logout.action = logout
		</value>

五、编写认证的realm

//realm的认证方法,从数据库查询用户信息
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
		AuthenticationToken token) throws AuthenticationException {
	
	// token是用户输入的用户名和密码 
	// 第一步从token中取出用户名
	String userCode = (String) token.getPrincipal();

	// 第二步:根据用户输入的userCode从数据库查询
	SysUser sysUser = null;
	try {
		sysUser = sysService.findSysUserByUserCode(userCode);
	} catch (Exception e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
	}

	// 如果查询不到返回null
	if(sysUser==null){//
		return null;
	}
	// 从数据库查询到密码
	String password = sysUser.getPassword();
	
	//盐
	String salt = sysUser.getSalt();

	// 如果查询到返回认证信息AuthenticationInfo
	
	//activeUser就是用户身份信息
	ActiveUser activeUser = new ActiveUser();
	
	activeUser.setUserid(sysUser.getId());
	activeUser.setUsercode(sysUser.getUsercode());
	activeUser.setUsername(sysUser.getUsername());
	//..
	
	//根据用户id取出菜单
	List<SysPermission> menus  = null;
	try {
		//通过service取出菜单 
		menus = sysService.findMenuListByUserId(sysUser.getId());
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	//将用户菜单 设置到activeUser
	activeUser.setMenus(menus);

	//将activeUser设置simpleAuthenticationInfo
	SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
			activeUser, password,ByteSource.Util.bytes(salt), this.getName());

	return simpleAuthenticationInfo;
}

六、设置凭证匹配器###

数据库中存储到的md5的散列值,在realm中需要设置数据库中的散列值它使用散列算法 及散列次数,让shiro进行散列对比时和原始数据库中的散列值使用的算法 一致。

 <!-- 凭证匹配器 -->
<bean id="credentialsMatcher"
	class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
	<property name="hashAlgorithmName" value="md5" />
	<property name="hashIterations" value="1" />
</bean>

七、认证通过的Controller

//系统首页
@RequestMapping("/first")
public String first(Model model)throws Exception{
	
	//从shiro的session中取activeUser
	Subject subject = SecurityUtils.getSubject();
	//取身份信息
	ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
	//通过model传到页面
	model.addAttribute("activeUser", activeUser);
	
	return "/first";
}

5、授权的实现

一、授权流程

在applicationContext-shiro.xml中配置url所对应的权限。

授权流程:
1、在applicationContext-shiro.xml中配置filter规则

/items/queryItems.action = perms[item:query]
2、用户在认证通过后,请求/items/queryItems.action
3、被PermissionsAuthorizationFilter拦截,发现需要“item:query”权限
4、PermissionsAuthorizationFilter调用realm中的doGetAuthorizationInfo获取数据库中正确的权限
5、PermissionsAuthorizationFilter对item:query 和从realm中获取权限进行对比,如果“item:query”在realm返回的权限列表中,授权通过。

二、配置授权不通过的拒绝页面

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
		<property name="loginUrl" value="/login.action" />
		<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
		<property name="successUrl" value="/first.action"/>
		<!-- 通过unauthorizedUrl指定没有权限操作时跳转页面-->
		<property name="unauthorizedUrl" value="/refuse.jsp" />

三、此种授权方式存在的问题

1、在applicationContext-shiro.xml中配置过虑器链接,需要将全部的url和权限对应起来进行配置,比较发麻不方便使用。

2、每次授权都需要调用realm查询数据库,对于系统性能有很大影响,可以通过shiro缓存来解决

四、Shiro的过滤器

过滤器简称     对应的java类
 Anon     org.apache.shiro.web.filter.authc.AnonymousFilter
 Authc     org.apache.shiro.web.filter.authc.FormAuthenticationFilter
 authcBasic     org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
 perms     org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
 port     org.apache.shiro.web.filter.authz.PortFilter
 rest     org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
 roles     org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
 ssl     org.apache.shiro.web.filter.authz.SslFilter
 user     org.apache.shiro.web.filter.authc.UserFilter
 logout     org.apache.shiro.web.filter.authc.LogoutFilter

anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,FormAuthenticationFilter是表单认证,没有参数
perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms ["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
user:例如/admins/user/**=user没有参数表示必须存在用户, 身份认证通过或通过记住我认证通过的可以访问,当登入操作时不做检查

五、授权realm的实现

// 用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
		PrincipalCollection principals) {
	
	//从 principals获取主身份信息
	//将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型),
	ActiveUser activeUser =  (ActiveUser) principals.getPrimaryPrincipal();
	
	//根据身份信息获取权限信息
	//从数据库获取到权限数据
	List<SysPermission> permissionList = null;
	try {
		permissionList = sysService.findPermissionListByUserId(activeUser.getUserid());
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	//单独定一个集合对象 
	List<String> permissions = new ArrayList<String>();
	if(permissionList!=null){
		for(SysPermission sysPermission:permissionList){
			//将数据库中的权限标签 符放入集合
			permissions.add(sysPermission.getPercode());
		}
	}
	
	
/*	List<String> permissions = new ArrayList<String>();
	permissions.add("user:create");//用户的创建
	permissions.add("item:query");//商品查询权限
	permissions.add("item:add");//商品添加权限
	permissions.add("item:edit");//商品修改权限**/
	//查到权限数据,返回授权信息(要包括 上边的permissions)
	SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
	//将上边查询到授权信息填充到simpleAuthorizationInfo对象中
	simpleAuthorizationInfo.addStringPermissions(permissions);

	return simpleAuthorizationInfo;
}

六、开启controller的aop支持

<!-- 开启aop,对类代理 -->
<aop:config proxy-target-class="true"></aop:config>
<!-- 开启shiro注解支持 -->
	<bean
	class="
org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
	<property name="securityManager" ref="securityManager" />
</bean>

七、在controller中添加注解完成授权

//商品信息方法
	@RequestMapping("/queryItems")
	@RequiresPermissions("item:query")//执行queryItems需要"item:query"权限
	public ModelAndView queryItems(HttpServletRequest request) throws Exception {
		
		System.out.println(request.getParameter("id"));
	
		//调用service查询商品列表
		List<ItemsCustom> itemsList = itemsService.findItemsList(null);

		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("itemsList", itemsList);
		// 指定逻辑视图名
		modelAndView.setViewName("itemsList");

		return modelAndView;
	}	

八、jsp页面通过标签授权

Jsp页面添加:
<%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %>

标签名称     标签条件(均是显示标签内容)
shiro:authenticated 登录之后
shiro:notAuthenticated 不在登录状态时
shiro:guest 用户在没有RememberMe时
shiro:user 用户在RememberMe时
<shiro:hasAnyRoles name="abc,123" > 在有abc或者123角色时
<shiro:hasRole name="abc"> 拥有角色abc
<shiro:lacksRole name="abc"> 没有角色abc
<shiro:hasPermission name="abc"> 拥有权限资源abc
<shiro:lacksPermission name="abc"> 没有abc权限资源
shiro:principal 显示用户身份名称
<shiro:principal property="username"/> 显示用户身份中的属性值
jsp页面实例:

<td>
	<!-- 有item:update权限才显示修改链接,没有该 权限不显示,相当 于if(hasPermission(item:update)) -->
	<shiro:hasPermission name="item:update">
	<a href="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a>
	</shiro:hasPermission>
	</td>

6、配置session管理器

和shiro整合后,使用shiro的session管理,shiro提供sessionDao操作 会话数据。

配置sessionManager

<!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customRealm" />
		<!-- 注入session管理器 -->
		<property name="sessionManager" ref="sessionManager" />
	</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <!-- session的失效时长,单位毫秒 -->
    <property name="globalSessionTimeout" value="600000"/>
    <!-- 删除失效的session -->
    <property name="deleteInvalidSessions" value="true"/>
</bean>

7、shiro缓存

一、缓存流程

shiro中提供了对认证信息和授权信息的缓存。shiro默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的。主要研究授权信息缓存,因为授权的数据量大。

用户认证通过。
该 用户第一次授权:调用realm查询数据库
该 用户第二次授权:不调用realm查询数据库,直接从缓存中取出授权信息(权限标识符)。

二、配置缓存管理器

使用ehcache进行缓存管理。

<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    	<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
    </bean>
!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customRealm" />
		<!-- 注入缓存管理器 -->
		<property name="cacheManager" ref="cacheManager"/>
		<!-- 注入session管理器 -->
		<property name="sessionManager" ref="sessionManager" />	
	</bean>

三、编写ehcache的配置文件

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
	<!--diskStore:缓存数据持久化的目录 地址  -->
	<diskStore path="F:developehcache" />
	<defaultCache 
		maxElementsInMemory="1000" 
		maxElementsOnDisk="10000000"
		eternal="false" 
		overflowToDisk="false" 
		diskPersistent="false"
		timeToIdleSeconds="120"
		timeToLiveSeconds="120" 
		diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
</ehcache>

四、缓存清空

如果用户正常退出,缓存自动清空。

如果用户非正常退出,缓存自动清空。

如果修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。
需要手动进行编程实现:
在权限修改后调用realm的clearCache方法清除缓存。
下边的代码正常开发时要放在service中调用。
在service中,权限修改后调用realm的方法。

//清除缓存
	public void clearCached() {
		PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
		super.clearCache(principals);
	}

编写controller

//注入realm
@Autowired
private CustomRealm customRealm;

@RequestMapping("/clearShiroCache")
public String clearShiroCache(){
	
	//清除缓存,将来正常开发要在service调用customRealm.clearCached()
	customRealm.clearCached();
	
	return "success";
}

8、验证码的实现

一、验证码的生成

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.Random"%>
<%@ page import="java.io.OutputStream"%>
<%@ page import="java.awt.Color"%>
<%@ page import="java.awt.Font"%>
<%@ page import="java.awt.Graphics"%>
<%@ page import="java.awt.image.BufferedImage"%>
<%@ page import="javax.imageio.ImageIO"%>
<%
	int width = 60;
	int height = 32;
	//create the image
	BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	Graphics g = image.getGraphics();
	// set the background color
	g.setColor(new Color(0xDCDCDC));
	g.fillRect(0, 0, width, height);
	// draw the border
	g.setColor(Color.black);
	g.drawRect(0, 0, width - 1, height - 1);
	// create a random instance to generate the codes
	Random rdm = new Random();
	String hash1 = Integer.toHexString(rdm.nextInt());
	System.out.print(hash1);
	// make some confusion
	for (int i = 0; i < 50; i++) {
		int x = rdm.nextInt(width);
		int y = rdm.nextInt(height);
		g.drawOval(x, y, 0, 0);
	}
	// generate a random code
	String capstr = hash1.substring(0, 4);
	//将生成的验证码存入session
	session.setAttribute("validateCode", capstr);
	g.setColor(new Color(0, 100, 0));
	g.setFont(new Font("Candara", Font.BOLD, 24));
	g.drawString(capstr, 8, 24);
	g.dispose();
	//输出图片
	response.setContentType("image/jpeg");
	out.clear();
	out = pageContext.pushBody();
	OutputStream strm = response.getOutputStream();
	ImageIO.write(image, "jpeg", strm);
	strm.close();
%>

二、在登录页面加入验证码

<TR>
							<TD>验证码:</TD>
							<TD><input id="randomcode" name="randomcode" size="8" /> <img
								id="randomcode_img" src="${baseurl}validatecode.jsp" alt=""
								width="56" height="20" align='absMiddle' /> <a
								href=javascript:randomcode_refresh()>刷新</a></TD>
						</TR>

三、自定义FormAuthenticationFilter过滤器

public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {

	//原FormAuthenticationFilter的认证方法
	@Override
	protected boolean onAccessDenied(ServletRequest request,
			ServletResponse response) throws Exception {
		//在这里进行验证码的校验
		
		//从session获取正确验证码
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpSession session =httpServletRequest.getSession();
		//取出session的验证码(正确的验证码)
		String validateCode = (String) session.getAttribute("validateCode");
		
		//取出页面的验证码
		//输入的验证和session中的验证进行对比 
		String randomcode = httpServletRequest.getParameter("randomcode");
		if(randomcode!=null && validateCode!=null && !randomcode.equals(validateCode)){
			//如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中
			httpServletRequest.setAttribute("shiroLoginFailure", "randomCodeError");
			//拒绝访问,不再校验账号和密码 
			return true; 
		}
		return super.onAccessDenied(request, response);
	}

		
}

四、配置自定义FormAuthenticationFilter过滤器

<!-- Shiro 的Web过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
		<property name="loginUrl" value="/login.action" />
		<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
		<property name="successUrl" value="/first.action"/>
		<!-- 通过unauthorizedUrl指定没有权限操作时跳转页面-->
		<property name="unauthorizedUrl" value="/refuse.jsp" />
		<!-- 自定义filter配置 -->
		<property name="filters">
			<map>
				<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中-->
				<entry key="authc" value-ref="formAuthenticationFilter" />
			</map>
		</property>

<!-- 自定义form认证过虑器 -->
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
	<bean id="formAuthenticationFilter" 
	class="cn.itcast.ssm.shiro.CustomFormAuthenticationFilter ">
		<!-- 表单中账号的input名称 -->
		<property name="usernameParam" value="username" />
		<!-- 表单中密码的input名称 -->
		<property name="passwordParam" value="password" />
 </bean>

五、在login.action对验证错误 进行解析

public String login(HttpServletRequest request)throws Exception{
		
		//如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
		String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
		//根据shiro返回的异常类路径判断,抛出指定异常信息
		if(exceptionClassName!=null){
			if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
				//最终会抛给异常处理器
				throw new CustomException("账号不存在");
			} else if (IncorrectCredentialsException.class.getName().equals(
					exceptionClassName)) {
				throw new CustomException("用户名/密码错误");
			} else if("randomCodeError".equals(exceptionClassName)){
				throw new CustomException("验证码错误 ");
			}else {
				throw new Exception();//最终在异常处理器生成未知错误
			}
		}
		//此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
		//登陆失败还到login页面
		return "login";
	}		

六、在filter配置匿名访问验证码jsp

<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
	<property name="filterChainDefinitions">
		<value>
			<!-- 对静态资源设置匿名访问 -->
			/images/** = anon
			/js/** = anon
			/styles/** = anon
			<!-- 验证码,可匿名访问 -->
			/validatecode.jsp = anon

9、记住我实现

一、 用户身份实现java.io.Serializable接口

二、配置rememeberMeManager

<!-- rememberMeManager管理器,写cookie,取出cookie生成用户信息 -->
	<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
		<property name="cookie" ref="rememberMeCookie" />
	</bean>
	<!-- 记住我cookie -->
	<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
		<!-- rememberMe是cookie的名字 -->
		<constructor-arg value="rememberMe" />
		<!-- 记住我cookie生效时间30天 -->
		<property name="maxAge" value="2592000" />
	</bean>

<!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customRealm" />
		<!-- 注入缓存管理器 -->
		<property name="cacheManager" ref="cacheManager"/>
		<!-- 注入session管理器 -->
		<property name="sessionManager" ref="sessionManager" />
		<!-- 记住我 -->
		<property name="rememberMeManager" ref="rememberMeManager"/>
		
	</bean>

三、在登录页面加入记住我选项

<tr>
		<TD></TD>
		<td><input type="checkbox" name="rememberMe" />自动登陆</td>
</tr>

四、配置rememberMe的input名称

<!-- 自定义form认证过虑器 -->
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
	<bean id="formAuthenticationFilter" 
	class="cn.itcast.ssm.shiro.CustomFormAuthenticationFilter ">
		<!-- 表单中账号的input名称 -->
		<property name="usernameParam" value="username" />
		<!-- 表单中密码的input名称 -->
		<property name="passwordParam" value="password" />
		<!-- 记住我input的名称 -->
		<property name="rememberMeParam" value="rememberMe"/>
 </bean>

五、使用UserFilter

如果设置记住我,下次访问某些url时可以不用登陆。将记住我即可访问的地址配置让UserFilter拦截。

	<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
	<property name="filterChainDefinitions">
		<value>
			<!-- 对静态资源设置匿名访问 -->
			/images/** = anon
			/js/** = anon
			/styles/** = anon
			<!-- 验证码,可匿名访问 -->
			/validatecode.jsp = anon
			
			<!-- 请求 logout.action地址,shiro去清除session-->
			/logout.action = logout
			<!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 -->
			<!-- /items/queryItems.action = perms[item:query]
			/items/editItems.action = perms[item:edit] -->
			<!-- 配置记住我或认证通过可以访问的地址 -->
			/index.jsp  = user
			/first.action = user
			/welcome.jsp = user
			<!-- /** = authc 所有url都必须认证通过才可以访问-->
			/** = authc
			<!-- /** = anon所有url都可以匿名访问 -->
			
		</value>
	</property>
原文地址:https://www.cnblogs.com/jack1995/p/7450401.html