学习目标:
1、了解验证码的使用
2、了解rememberme的使用
学习过程:
一、验证码
1、自定义FormAuthenticationFilter,在验证账号和名称之前校验验证码。
public class VerCodeFormAuthenticationFilter extends FormAuthenticationFilter { protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { // 校验验证码 // 从session获取正确的验证码 HttpSession session = ((HttpServletRequest) request).getSession(); // 页面输入的验证码 String randomcode = request.getParameter("randomcode"); // 从session中取出验证码 String vercode = (String) session.getAttribute("vercode"); if (vercode != null && randomcode != null && !vercode.equalsIgnoreCase(randomcode)) { // 如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中 request.setAttribute("shiroLoginFailure", "randomCodeError"); // 拒绝访问,不再校验账号和密码 return true; } return super.onAccessDenied(request, response, mappedValue); } }
2、配置匿名访问
验证码部分代码:
@Controller @RequestMapping("/") public class VerifyCodeControl { @RequestMapping("/cerCode") public void getAuthCode(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); // 生成随机字串 String verifyCode = VerifyCodeUtils.generateVerifyCode(4); // 存入会话session session.setAttribute("vercode", verifyCode.toLowerCase()); // 生成图片 int w = 168, h = 33; VerifyCodeUtils.outputImage(w, h, response.getOutputStream(), verifyCode); } }
修改shiro的配置,验证码的路径不需要权限拦截
/cerCode.do = anon
3、FormAuthenticationFilter配置
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
<bean id="verCodeFormAuthenticationFilter" class="com.shiro.myfilter.VerCodeFormAuthenticationFilter"> <property name="usernameParam" value="usernamemy" /> <property name="passwordParam" value="passwordmy" /> </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.do" /> <property name="unauthorizedUrl" value="/refuse.do" /> <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 --> <property name="filters"> <map> <entry key="authc" value-ref="verCodeFormAuthenticationFilter" /> </map> </property> ......下面省略
3、登陆页面
添加验证码,注意名称默认就是randomcode
<TD>验证码:<input id="randomcode" name="randomcode" size="8" /> <img id="randomcode_img" src="cerCode.do"align='absMiddle' /></TD>
二、记住我
1、记住我的实现原理
用户登陆选择“自动登陆”本次登陆成功会向cookie写身份信息,下次登陆从cookie中取出身份信息实现自动登陆,使用身份验证和使用记住我的方式进行验证时不一样的,已办来说使用身份验证的安全性高一点。如果你的网站安全性要求比较高,建议还是使用身份验证。因为记住我的认证时把登陆信息保存在浏览器的cookie里面,如果你的电脑让别人用了,或者在其他人的电脑上面使用了记住我的功能,那么别人就可以随时登陆了。再有cookie也有给窃取的可能性。
在shiro中,你可以通过方法判断subject.isAuthenticated()表示用户进行了身份验证登录的,即使有Subject.login进行了登录;subject.isRemembered():表示用户是通过记住我登录的;且两者二选一,即subject.isAuthenticated()==true,则subject.isRemembered()==false;反之一样。
如果要自己做RememeberMe,需要在登录之前这样创建Token:UsernamePasswordToken(用户名,密码,是否记住我),如:
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
subject.login(token);
另外在权限也需要进行相关的修改
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> …… <property name="filterChainDefinitions"> <value> /logout.do = logout <!-- 改成user,这样就可以使用rememberme访问了。 --> /login.do = authc /** = user </value> </property> </bean>
/authenticated.do = authc,如果使用authc表示访问该地址用户必须身份验证通过(Subject. isAuthenticated()==true);而“/** = user”中的user表示访问该地址的用户是身份验证通过或RememberMe登录的都可以。
还有一个使用前提条件,如果使用了对象保存用户身份,该用户对象需要实现java.io.Serializable接口,因为需要序列化保存在前端的cookie中。
public class User implements java.io.Serializable { private String userId;//用户id private String loginName;// 用户账号 private String userName;// 用户名称 private String password;//用户密码 private String salt;//盐
2、配置rememberMeManager
<!-- 记住我cookie --> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <!-- cookie的名字 --> <constructor-arg value="javadayup_v_1"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="2592000"/><!-- 30天时间,记住我30天 --> </bean> <!-- rememberMeManager管理器 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <property name="cookie" ref="rememberMeCookie" /> <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)--> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('sdfERT567s0KTA3Kprsdag==')}"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myCustomRealm" /> <property name="cacheManager" ref="cacheManager" /> <property name="sessionManager" ref="sessionManager" /> <!-- 记住我 --> <property name="rememberMeManager" ref="rememberMeManager"/> </bean>
3、FormAuthenticationFilter配置
修改formAuthenticationFitler添加页面中“记住我checkbox”的input名称,不用配置也可以,默认就是rememberMe
<bean id="formAuthenticationFilter"
class="cn.itcast.ssm.shiro.MyFormAuthenticationFilter">
<!-- 表单中账号的input名称 -->
<property name="usernameParam" value="usercode" />
<!-- 表单中密码的input名称 -->
<property name="passwordParam" value="password" />
<property name="rememberMeParam" value="rememberMe"/>
</bean>
4、登陆页面
在login.jsp中添加“记住我”checkbox。
<TR> <TD> <input type="checkbox" name="rememberMe" />自动登陆 </TD> </TR>