shiro表单的验证 自定义FormAuthenticationFilter

本文介绍如何在Shiro认证框架中集成验证码验证功能,并实现记住我功能,确保用户下次自动登录。文章详细说明了自定义FormAuthenticationFilter以添加验证码校验的过程,同时展示了如何配置记住我功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

验证码思路;shiro使用FormAuthenticationFilter进行表单认证,验证校验的功能应该加在FormAuthenticationFilter中,在认证之前进行验证码校验。

需要写FormAuthenticationFilter的子类,继承FormAuthenticationFilter,改写它的认证方法,在认证之前进行验证码校验。

自定义FormAuthenticationFilter
[html] view plain copy
package cn.me.ssm.shiro;  
  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpSession;  
  
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;  
  
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {  
  
    @Override  
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {  
        // 在这里进行验证码的校验  
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;  
        HttpSession session = httpServletRequest.getSession();  
  
        // 取出验证码  
        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);  
    }  
}  

spirng-shiro.xml修改
[html] view plain copy
<!-- Shiro过滤器 -->  
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,这个属性是必须的 -->  
        <property name="securityManager" ref="securityManager" />  
        <!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->  
        <property name="loginUrl" value="/login.do" />  
        <!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->  
        <property name="successUrl" value="/first.do" />  
        <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->  
        <property name="unauthorizedUrl" value="/refuse.jsp" />  
  
        <!-- 自定义filter配置 -->  
        <property name="filters">  
            <map>  
                <!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中 -->  
                <entry key="authc" value-ref="formAuthenticationFilter" />  
            </map>  
        </property>  
  
        <!-- Shiro连接约束配置,即过滤链的定义 -->  
        <property name="filterChainDefinitions">  
            <value>  
                <!-- /** = anon所有url都可以匿名访问 -->  
                <!-- 对静态资源设置匿名访问 -->  
                /images/** = anon  
                /js/** = anon  
                /styles/** = anon  
                <!-- 验证码,可匿名访问 -->  
                /validatecode.jsp = anon  
  
                <!-- 请求 logout.action地址,shiro去清除session -->  
                /logout.action = logout  
                <!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 -->  
                <!-- /items/queryItems.action = perms[item:query] -->  
                <!-- /** = authc 所有url都必须认证通过才可以访问 -->  
                /**=authc  
  
            </value>  
        </property>  
    </bean>  
  
    <!-- 自定义form认证过虑器 -->  
    <!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->  
    <bean id="formAuthenticationFilter" class="cn.me.ssm.shiro.CustomFormAuthenticationFilter ">  
        <!-- 表单中账号的input名称 -->  
        <property name="usernameParam" value="username" />  
        <!-- 表单中密码的input名称 -->  
        <property name="passwordParam" value="password" />  
    </bean>  


在login.do对验证错误 进行解析
[html] view plain copy
//登陆提交地址,和applicationContext-shiro.xml中配置的loginurl一致  
    @RequestMapping("/login")  
    public String login(HttpServletRequest request) throws Exception {  
  
        // 如果登录失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名  
        // 根据shiro返回的异常类路径判断,抛出指定异常信息  
        String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");  
        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";  
    }  


记住我
用户登陆选择“自动登陆”本次登陆成功会向cookie写身份信息,下次登陆从cookie中取出身份信息实现自动登陆。
用户身份实现Java.io.Serializable接口
向cookie记录身份信息需要用户身份信息对象实现序列化接口,如下:
[html] view plain copy
package cn.me.ssm.po;  
  
import java.io.Serializable;  
import java.util.List;  
  
/**  
 * 用户身份信息  
 *   
 * @author Administrator  
 *  
 */  
public class ActiveUser implements Serializable {  
    /**  
     *   
     */  
    private static final long serialVersionUID = -60165487594776678L;  
    private String userid;// 用户id  
    private String usercode;// 用户帐号  
    private String username;// 用户名称  
  
    private List<SysPermission> menus;// 用户的菜单  
    private List<SysPermission> permissions;// 权限  
  
    public String getUserid() {  
        return userid;  
    }  
  
    public void setUserid(String userid) {  
        this.userid = userid;  
    }  
  
    public String getUsercode() {  
        return usercode;  
    }  
  
    public void setUsercode(String usercode) {  
        this.usercode = usercode;  
    }  
  
    public String getUsername() {  
        return username;  
    }  
  
    public void setUsername(String username) {  
        this.username = username;  
    }  
  
    public List<SysPermission> getMenus() {  
        return menus;  
    }  
  
    public void setMenus(List<SysPermission> menus) {  
        this.menus = menus;  
    }  
  
    public List<SysPermission> getPermissions() {  
        return permissions;  
    }  
  
    public void setPermissions(List<SysPermission> permissions) {  
        this.permissions = permissions;  
    }  
  
}  

spring-shiro.xml 修改
[html] view plain copy
<!-- Shiro过滤器 -->  
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
    <!-- Shiro的核心安全接口,这个属性是必须的 -->  
    <property name="securityManager" ref="securityManager" />  
    <!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->  
    <property name="loginUrl" value="/login.do" />  
    <!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->  
    <property name="successUrl" value="/first.do" />  
    <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->  
    <property name="unauthorizedUrl" value="/refuse.jsp" />  
  
    <!-- 自定义filter配置 -->  
    <property name="filters">  
        <map>  
            <!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中 -->  
            <entry key="authc" value-ref="formAuthenticationFilter" />  
        </map>  
    </property>  
  
    <!-- Shiro连接约束配置,即过滤链的定义 -->  
    <property name="filterChainDefinitions">  
        <value>  
            <!-- /** = anon所有url都可以匿名访问 -->  
            <!-- 对静态资源设置匿名访问 -->  
            /images/** = anon  
            /js/** = anon  
            /styles/** = anon  
            <!-- 验证码,可匿名访问 -->  
            /validatecode.jsp = anon  
  
            <!-- 请求 logout.action地址,shiro去清除session -->  
            /logout.action = logout  
            <!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 -->  
            <!-- /items/queryItems.action = perms[item:query] -->  
            <!-- 配置记住我或认证通过可以访问的地址 -->  
            /** = user  
            <!-- /** = authc 所有url都必须认证通过才可以访问 -->  
            /**=authc  
  
        </value>  
    </property>  
</bean>  
  
<!-- 自定义form认证过虑器 -->  
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->  
<bean id="formAuthenticationFilter" class="cn.me.ssm.shiro.CustomFormAuthenticationFilter ">  
    <!-- 表单中账号的input名称 -->  
    <property name="usernameParam" value="username" />  
    <!-- 表单中密码的input名称 -->  
    <property name="passwordParam" value="password" />  
    <!-- 记住我input的名称 -->  
    <property name="rememberMeParam" value="rememberMe"/>  
</bean>  
  
<!-- 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>  
  
<!-- 安全管理器 -->  
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
    <!-- 注入自定义Realm -->  
    <property name="realm" ref="customRealm" />  
    <!-- 注入缓存管理器 -->  
    <property name="cacheManager" ref="cacheManager" />  
    <!-- 注入session管理器 -->  
    <property name="sessionManager" ref="sessionManager" />  
    <!-- 记住我 -->  
    <property name="rememberMeManager" ref="rememberMeManager"/>  
</bean>  



登陆页面
[html] view plain copy
<tr>  
                            <TD></TD>  
                            <td><input type="checkbox" name="rememberMe" />自动登陆</td>  
                        </tr>  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值