spring shiro登录验证码与记住登录实现

2018年03月01日 09:53 | 5579次浏览

一、前言

上一章节通过注解和缓存做了权限验证,这里增加验证码与记住登录功能。注意: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;

/**
 * 
 */
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"  onclick="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

如图:可以访问欢迎页面,不能访问商品管理页面。

shiro登录验证码

总结记住登录:设置记住登录管理器====注入securityManager=======设置input=============设置选择框name属性==========设置user拦截器访问页面


user拦截器“

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

---------摘录自ycy博文




小说《我是全球混乱的源头》

感觉本站内容不错,读后有收获?小额赞助,鼓励网站分享出更好的教程