一、前言
前面通过注解和缓存做了权限验证,这里增加验证码与记住登录功能。注意:shiro缓存是权限授权的缓存。
二、验证码
2.1编写继承FormAuthenticationFilter的权限验证自定义类
重写一个验证验证码的onAccessDenied方法
CustomFormAuthenticationFilter.java
package com.ycy.shiro;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* Created by Administrator on 2015/10/20 0020.
*/
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
// 校验验证码
// 从session获取正确的验证码
HttpSession session = ((HttpServletRequest)request).getSession();
//页面输入的验证码
String randomcode = request.getParameter("randomcode");
//从session中取出验证码
String validateCode = (String) session.getAttribute("validateCode");
if (randomcode!=null&&validateCode!=null&&!randomcode.equals(validateCode)) {
// randomCodeError表示验证码错误
request.setAttribute("shiroLoginFailure", "randomCodeError");
//拒绝访问,不再校验账号和密码
return true;
}
return super.onAccessDenied(request, response, mappedValue);
}
}
2.2 登录获取我们自定义验证
package com.ycy.controller;
import com.ycy.Exception.CustomException;
import com.ycy.model.ActiveUser;
import com.ycy.service.SysService;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
*
* <p>Title: LoginController</p>
* <p>Description: 登陆和退出</p>
*/
@Controller
public class LoginController {
@Autowired
private SysService sysService;
//用户登陆提交方法
@RequestMapping("/login")
public String login(HttpServletRequest request)throws Exception{
//如果登录失败从request中获取认证异常信息,shrioLoginFailure就是shiro异常类的全限定名
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
//根据shrio返回的异常路径判断,抛出指定异常信息
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("未知错误");
}
}
return "login";
}
}
2.3 注入自定义的FormAuthenticationFilter
在applicationContext中注入我们自己定义的验证器
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd ">
<!-- Shiro 的Web过滤器 -->
<!--================================================1、与web.xml对应的bean===================================-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 如果没有认证将要跳转的登陆地址,http可访问的url,如果不在表单认证过虑器FormAuthenticationFilter中指定此地址就为身份认证地址 -->
<property name="loginUrl" value="/login" />
<!-- 没有权限跳转的地址 -->
<property name="unauthorizedUrl" value="/pages/jsp/refuse.jsp" />
<!-- 自定义filter配置 -->
<property name="filters">
<map>
<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中-->
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>
<!--过滤定义,从上而下,蒋匿名的anon放最下面-->
<property name="filterChainDefinitions">
<value>
<!--静态资源通过-->
/js/** anon
/images/** anon
/styles/** anon
<!-- 验证码,可匿名访问 -->
/pages/jsp/validatecode.jsp = anon
<!--商品查询需要商品查询权限(权限表达式)尽量有注解-->
<!--/items/queryItems=perms[item:query]-->
<!--表示所有请求url必须通过认证-->
/**= authc
<!--请求logout,shrio擦除sssion-->
/logout=logout
<!--表示所有url都可以通过-->
<!-- /** anon-->
</value>
</property>
</bean>
<!-- ==============================================2、安全管理器============================================== -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<!--缓存管理-->
<property name="sessionManager" ref="sessionManager" />
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:cache/ehcache.xml"/>
</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>
<!-- 自定义form认证过虑器 -->
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
<bean id="formAuthenticationFilter" class="com.ycy.shiro.CustomFormAuthenticationFilter">
<!--表单中账户和密码的input框名称-->
<property name="usernameParam" value="username"/>
<property name="passwordParam" value="password"/>
</bean>
<!--==============================================3、realm===================================================-->
<!-- Shiro配置,继承自AuthorizingRealm的自定义Realm (解决初始化时的依赖循环问题,通过这里向realm中注入userservice实现)-->
<bean id="userRealm" class="com.ycy.shiro.CustomRealm" >
<property name="authorizationCacheName" value="authorizationcache" />
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!--4 凭证匹配器 -->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="1" />
</bean>
</beans>
2.4 在页面编写验证码
<TR>
<TD>验证码:</TD>
<TD><input id="randomcode" name="randomcode" size="8" /> <img id="randomcode_img" alt=""
width="56" height="20" align='absMiddle' src="${baseurl}pages/jsp/validatecode.jsp" οnclick="randomcode_refresh()"/> <a
href=javascript:randomcode_refresh()>刷新</a></TD>
</TR>
2.5 设置验证码能够匿名访问
<value>
<!--静态资源通过-->
/js/** anon
/images/** anon
/styles/** anon
<!-- 验证码,可匿名访问 -->
/pages/jsp/validatecode.jsp = anon
<!--请求logout,shrio擦除sssion-->
/logout=logout
<!--商品查询需要商品查询权限(权限表达式)尽量有注解-->
<!--/items/queryItems=perms[item:query]-->
<!--表示所有请求url必须通过认证-->
/**= authc
<!--表示所有url都可以通过-->
<!-- /** anon-->
</value>
</property>
验证码页面图片:
三、记住登录设置
就是写入cookie,shrio本身就支持。
1、用户序列号
public class SysPermission implements Serializable{
private Long id;
private String name;
private String type;
private String url;
private String percode;
private Long parentid;
2、记住登录xml配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd ">
<!-- Shiro 的Web过滤器 -->
<!--================================================1、与web.xml对应的bean===================================-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 如果没有认证将要跳转的登陆地址,http可访问的url,如果不在表单认证过虑器FormAuthenticationFilter中指定此地址就为身份认证地址 -->
<property name="loginUrl" value="/login" />
<!-- 没有权限跳转的地址 -->
<property name="unauthorizedUrl" value="/pages/jsp/refuse.jsp" />
<!-- 自定义filter配置 -->
<property name="filters">
<map>
<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中-->
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>
<!--过滤定义,从上而下,蒋匿名的anon放最下面-->
<property name="filterChainDefinitions">
<value>
<!--静态资源通过-->
/js/** anon
/images/** anon
/styles/** anon
<!-- 验证码,可匿名访问 -->
/pages/jsp/validatecode.jsp = anon
<!--请求logout,shrio擦除sssion-->
/logout=logout
<!--商品查询需要商品查询权限(权限表达式)尽量有注解-->
<!--/items/queryItems=perms[item:query]-->
<!-- 配置记住我或认证通过可以访问的地址 -->
/index.jsp = user
/first = user
/welcome.jsp = user
<!--表示所有请求url必须通过认证-->
/**= authc
<!--表示所有url都可以通过-->
<!-- /** anon-->
</value>
</property>
</bean>
<!-- ==============================================2、安全管理器============================================== -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<!--缓存管理-->
<property name="sessionManager" ref="sessionManager" />
<property name="cacheManager" ref="cacheManager"/>
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:cache/ehcache.xml"/>
</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>
<!-- 自定义form认证过虑器 -->
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
<bean id="formAuthenticationFilter" class="com.ycy.shiro.CustomFormAuthenticationFilter">
<!--表单中账户和密码的input框名称-->
<property name="usernameParam" value="username"/>
<property name="passwordParam" value="password"/>
<property name="rememberMeParam" value="rememberMe"/>
</bean>
<!--==============================================3、realm===================================================-->
<!-- Shiro配置,继承自AuthorizingRealm的自定义Realm (解决初始化时的依赖循环问题,通过这里向realm中注入userservice实现)-->
<bean id="userRealm" class="com.ycy.shiro.CustomRealm" >
<property name="authorizationCacheName" value="authorizationcache" />
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!--4 凭证匹配器 -->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="1" />
</bean>
<!--==============================================rememberMeManager管理器========================================-->
<!-- rememberMeManager管理器 -->
<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">
<constructor-arg value="rememberMe" />
<!-- 记住我cookie生效时间30天 -->
<property name="maxAge" value="2592000" />
</bean>
</beans>
1其中记住登录为
<!--==============================================rememberMeManager管理器========================================-->
<!-- rememberMeManager管理器 -->
<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">
<constructor-arg value="rememberMe" />
<!-- 记住我cookie生效时间30天 -->
<property name="maxAge" value="2592000" />
</bean>
2需要加入securityManager
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
3获取记住我的input属性
<bean id="formAuthenticationFilter" class="com.ycy.shiro.CustomFormAuthenticationFilter">
<!--表单中账户和密码的input框名称-->
<property name="usernameParam" value="username"/>
<property name="passwordParam" value="password"/>
<!--记住我input框名称-->
<property name="rememberMeParam" value="rememberMe"/>
</bean>
3、登录页面设置
<TR>
<TD></TD>
<TD>
<input type="checkbox" name="rememberMe" />自动登陆
</TD>
</TR>
4、测试记住登录
查询cookie是否有我们的记录,而且可以查询cookie用户页面,用到另一个过滤器 user。在securityManager配置过滤器
<!-- 配置记住我或认证通过可以访问的地址 -->
/index.jsp = user
/first = user
/welcome.jsp = user
如图:可以访问欢迎页面,不能访问商品管理页面。
总结记住登录:设置记住登录管理器====注入securityManager=======设置input=============设置选择框name属性==========设置user拦截器访问页面
user拦截器“
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查