验证码

在登陆的时候,我们一般都设置有验证码,但是我们如果使用Shiro的话,那么Shiro默认的是使用FormAuthenticationFilter进行表单认证。

而我们的验证校验的功能应该加在FormAuthenticationFilter中,在认证之前进行验证码校验

FormAuthenticationFilter是Shiro默认的功能,我们想要在FormAuthenticationFilter之前进行验证码校验,就需要继承FormAuthenticationFilter类,改写它的认证方法

自定义Form认证类


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);
} }

配置自定义类

我们编写完自定义类以后,是需要在Shiro配置文件中配置我们这个自定义类的。

由于这是我们自定义的,因此我们并不需要用户名就使用username,密码就使用password,这个也是我们可以自定义的


<!-- 自定义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>

在Shiro的bean中注入自定义的过滤器



        <!-- 自定义filter配置 -->
<property name="filters">
<map>
<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中-->
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>

在我们的Controller添加验证码错误的异常判断,从我们的Controller就可以发现,为什么我们要把错误信息存放在request域对象shiroLoginFailure,因为我们得在Controller中获取获取信息,从而给用户对应的提示



    @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";
}


<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>

记住我

Shiro还提供了记住用户名和密码的功能

用户登陆选择“自动登陆”本次登陆成功会向cookie写身份信息,下次登陆从cookie中取出身份信息实现自动登陆。

想要实现这个功能,我们的认证信息需要实现Serializable接口



public class ActiveUser implements java.io.Serializable {
private String userid;//用户id(主键)
private String usercode;// 用户账号
private String username;// 用户名称 private List<SysPermission> menus;// 菜单
private List<SysPermission> permissions;// 权限 }

配置rememeber管理器


<!-- 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"~~~····
<property name="cacheManager" ref="cacheManager"/>
<!-- 注入session管理器 -->
<property name="sessionManager" ref="sessionManager" />
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>

配置页面的input名称:


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

如果设置了“记住我”,那么访问某些URL的时候,我们就不需要登陆了。将记住我即可访问的地址配置让UserFilter拦截。

        <!-- 配置记住我或认证通过可以访问的地址 -->
/index.jsp = user
/first.action = user
/welcome.jsp = user

Shiro第六篇【验证码、记住我】的更多相关文章

  1. [老老实实学WCF] 第六篇 元数据交换

    老老实实学WCF 第六篇 元数据交换 通过前两篇的学习,我们了解了WCF通信的一些基本原理,我们知道,WCF服务端和客户端通过共享元数据(包括服务协定.服务器终结点信息)在两个 终结点上建立通道从而进 ...

  2. 解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译)

    解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译) http://improve.dk/orcamdf-rawdatabase-a-swiss-a ...

  3. 解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions(译)

    解剖SQLSERVER 第六篇  对OrcaMDF的系统测试里避免regressions (译) http://improve.dk/avoiding-regressions-in-orcamdf-b ...

  4. Python之路【第十六篇】:Django【基础篇】

    Python之路[第十六篇]:Django[基础篇]   Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...

  5. 第六篇 :微信公众平台开发实战Java版之如何自定义微信公众号菜单

    我们来了解一下 自定义菜单创建接口: http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_to ...

  6. RabbitMQ学习总结 第六篇:Topic类型的exchange

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  7. 第六篇 Replication:合并复制-发布

    本篇文章是SQL Server Replication系列的第六篇,详细内容请参考原文. 合并复制,类似于事务复制,包括一个发布服务器,一个分发服务器和一个或多个订阅服务器.每一个发布服务器上可以定义 ...

  8. 第六篇 Integration Services:初级工作流管理

    本篇文章是Integration Services系列的第六篇,详细内容请参考原文. 简介在前几篇文章中,我们关注使用增量加载方式加载数据.在本篇文章,我们将关注使用优先约束管理SSIS控制流中的工作 ...

  9. 第六篇 SQL Server安全执行上下文和代码签名

    本篇文章是SQL Server安全系列的第六篇,详细内容请参考原文. SQL Server决定主体是否有必要的执行代码权限的根本途径是其执行上下文规则.这一切都可能复杂一个主体有执行代码的权限,但是却 ...

随机推荐

  1. MySQL中count(1),count(*),count(col)的区别

    count(*)返回行数的时候不管列中的值是不是null,在MyISAM表中,count(*)被优化,因为在MyISAM表中,行数被额外存储了,所以会很快,但是这个时候不能有where条件.innod ...

  2. 一篇文章学会springMVC(转)

    说在前面 本文只是入门 为什么用springMVC?springMVC有什么有缺点?springMVC和Struts有什么区别?等等这些问题可以参考网路上资源,本文的重点是快速带入,让大家了解熟悉sp ...

  3. 【Hadoop】集群配置要点

    1.SSH免密码登录 1.1生成公钥,一直enter,直到完成 dream361@master:~$ ssh-keygen -t rsa 1.2传送公钥 dream361@master:~$ scp ...

  4. Ubuntu 14.04下Redis安装报错:“You need tcl 8.5 or newer in order to run the Redis test”问题解决

    Redis简介: Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工 ...

  5. 7.28.1 Spring构造注入还是设置注入

    1. 构造方法注入代码如下:public UserManagerImpl(UserDao userDao) {                                              ...

  6. Xcode修改包名(含cocopods)

    由于需要现在要更改包名,但是在网上找了N多资料都比较老,16年的资料却是残缺不全,尤其 ios10 出了 .entitlement  的机制 ,很多琐碎的小细节 很容易忘记.所以我自己总结了一篇. 注 ...

  7. Js原生轮播-直接上代码

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  8. Be the Best of Whatever You Are

    If you can't be a pine on the top of the hill, Be a scrub in the valley—but be The best little scrub ...

  9. ASP.NET 给Web中的网页添加Loading进度条形式

    前段时间客户提了一个需求,要求给网站中某些功能添加进度条形式,因为某些功能查询的数据量太大,经常会出现点击Search按钮,但是没有任何反应的情况,会让用户以为网站挂掉了,导致投诉的事情发生,所以客户 ...

  10. HTTP手记

    ---------------------tcp/ip模型和osi模型---------------------tcp/ip协议模型   osi模型应用层   应用层 表示层 会话层传输层   传输层 ...