springmvc集成shiro登录失败处理
一般的登录流程会有:用户名不存在,密码错误,验证码错误等..
在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理。
shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制。
shiro的会话管理和缓存管理不在本文范围内。
下面通过登录失败的处理流程来介绍springmvc与shiro的集成。
项目依赖:
| 依赖名称 | 版本 |
| spring | 4.1.4.RELEASE |
| shiro | 1.2.2 |
| self4j | 1.7.5 |
| log4j | 1.2.17 |
在web.xml里配置shiro
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
新建一个spring-context-shiro.xml配置shiro相关信息,使用spring加载
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"
default-lazy-init="true"> <description>Shiro Configuration</description>
<!-- 安全认证过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/sys/login" />
<property name="successUrl" value="/sys" />
<property name="filters">
<map>
<!--自定义登录验证过滤器-->
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
/sys/login = authc
/sys/logout = logout
/sys/** = user
</value>
</property>
</bean> <!-- 定义 Shiro 主要业务对象 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="systemAuthorizingRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 会话管理器,设定会话超时及保存 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 全局会话超时时间(单位毫秒),默认30分钟 -->
<property name="globalSessionTimeout" value="1800000" />
<property name="sessionDAO" ref="sessionDAO"/>
</bean>
<!-- 会话验证调度器,每30分钟执行一次验证 -->
<!-- <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> -->
<bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
<property name="interval" value="1800000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- sessionDAO保存认证信息 -->
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="activeSessionsCacheName" value="shiro-activeSessionCache" />
<property name="cacheManager" ref="shiroCacheManager" />
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 用户授权信息Cache, 采用EhCache -->
<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- Shiro生命周期处理器 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- AOP式方法级权限检查 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
</beans>
新建一个登录认证过滤器FormAuthenticationFilter.java
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Service; /**
* 表单验证(包含验证码)过滤类*/
@Service
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
public static final String DEFAULT_CAPTCHA_PARAM = "validateCode"; private String captchaParam = DEFAULT_CAPTCHA_PARAM; public String getCaptchaParam() {
return captchaParam;
} protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
} protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
String locale = request.getParameter("locale"); if (password == null) {
password = "";
}
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
String captcha = getCaptcha(request);
return new UsernamePasswordToken(username, password.toCharArray(),locale, rememberMe, host, captcha);
}
}
新建令牌类UsernamePasswordToken.java
package com.chunhui.webservice.modules.sys.security; /**
* 用户和密码(包含验证码)令牌类*/
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
private static final long serialVersionUID = 1L;
private String captcha;
private String locale; public String getCaptcha() {
return captcha;
} public void setCaptcha(String captcha) {
this.captcha = captcha;
} public String getLocale() {
return locale;
} public void setLocale(String locale) {
this.locale = locale;
} public UsernamePasswordToken() {
super();
} public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
}
public UsernamePasswordToken(String username, char[] password, String locale,boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
this.locale = locale;
}
}
最后一个是认证实现类SystemAuthorizationRealm:
package com.chunhui.webservice.modules.sys.security;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct; import com.chunhui.webservice.common.utils.EmployeeType;
import com.chunhui.webservice.common.utils.VertifyStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import com.chunhui.webservice.common.servlet.ValidateCodeServlet;
import com.chunhui.webservice.common.utils.SpringContextHolder;
import com.chunhui.webservice.modules.sys.entity.Employee;
import com.chunhui.webservice.modules.sys.entity.Menu;
import com.chunhui.webservice.modules.sys.service.SystemService;
import com.chunhui.webservice.modules.sys.utils.SystemUtils;
import com.chunhui.webservice.modules.sys.web.LoginController; /**
* 系统安全认证实现类*/
@Service
@DependsOn({ "employeeDao", "roleDao", "menuDao" })
public class SystemAuthorizingRealm extends AuthorizingRealm {
private SystemService systemService; /**
* 认证回调函数, 登录时调用
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
// 判断验证码
Session session = SecurityUtils.getSubject().getSession();
// 设置独立的session会话超时时间 session.setTimeout(60000);
String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)) {
throw new CaptchaException("验证码错误!");
}
//如果帐号不存在,输出
//throw new UnknownAccountException(); //如果帐号被禁用,输出
//throw new DisabledAccountException(); //保存登录时选择的语言
SecurityUtils.getSubject().getSession().setAttribute("locale", token.getLocale());
try{
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(new Principal(employee), employee.getPassword(), getName());
return info;
}catch (Throwable t){
t.printStackTrace();
throw new AuthenticationException();
}
}/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Principal principal = (Principal) getAvailablePrincipal(principals);
Employee employee = getSystemService().getEmployeeByName(principal.getUsername());
if (employee != null) {
SystemUtils.putCache("employee", employee);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List<Menu> list = SystemUtils.getMenuList();
for (Menu menu : list) {
if (StringUtils.isNotBlank(menu.getPermission())) {
// 添加基于Permission的权限信息
for (String permission : StringUtils.split(menu.getPermission(), ",")) {
info.addStringPermission(permission);
}
}
}
// 更新登录IP和时间
getSystemService().updateEmployeeLoginInfo(employee.getId());
return info;
} else {
return null;
}
} /**
* 清空用户关联权限认证,待下次使用时重新加载
*/
public void clearCachedAuthorizationInfo(String principal) {
SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
clearCachedAuthorizationInfo(principals);
} /**
* 清空所有关联认证
*/
public void clearAllCachedAuthorizationInfo() {
Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
if (cache != null) {
for (Object key : cache.keys()) {
cache.remove(key);
}
}
} /**
* 获取系统业务对象
*/
public SystemService getSystemService() {
if (systemService == null) {
systemService = SpringContextHolder.getBean(SystemService.class);
}
return systemService;
} /**
* 授权用户信息
*/
public static class Principal implements Serializable {
private static final long serialVersionUID = 1L; private String id;
private String username;
private String realname;
private Map<String, Object> cacheMap; public Principal(Employee employee) {
this.id = employee.getId();
this.username = employee.getUsername();
this.realname = employee.getRealname();
} public String getId() {
return id;
} public String getUsername() {
return username;
} public String getRealname() {
return realname;
} public Map<String, Object> getCacheMap() {
if (cacheMap == null) {
cacheMap = new HashMap<String, Object>();
}
return cacheMap;
}
}
}
那么在JSP页面,可以通过获取登录异常具体的异常类型来在页面显示错误原因
<%String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%>
<c:set var="exp_type" value="<%=error %>"/>
<c:set var="tips" value=""></c:set>
<c:if test="${fn:contains(exp_type,'CaptchaException')}">
<c:set var="tips" value="验证码错误"></c:set>
</c:if>
<c:if test="${fn:contains(exp_type,'FailVertifyException')}">
<c:set var="tips" value="该账号审核未通过,不允许登陆!"></c:set>
</c:if>
<c:if test="${fn:contains(exp_type,'NotVertifyException')}">
<c:set var="tips" value="该账号正在审核中... 不允许登陆!"></c:set>
</c:if>
<c:if test="${fn:contains(exp_type,'UnknownAccountException')}">
<c:set var="tips" value="账号不存在!"></c:set>
</c:if>
<c:if test="${fn:contains(exp_type,'DisabledAccountException')}">
<c:set var="tips" value="账号不允许登陆!"></c:set>
</c:if>
<c:if test="${fn:contains(exp_type,'IncorrectCredentialsException')}">
<c:set var="tips" value="密码错误!"></c:set>
</c:if>
springmvc集成shiro登录失败处理的更多相关文章
- springmvc集成shiro例子
仅供参考 仅供参考 登录部分 代码: @RequestMapping(value = "/login", method = RequestMethod.GET) @Response ...
- SpringMVC集成Shiro、读取数据库操作权限
1.Maven添加Shiro所需的jar包 <dependency> <groupId>org.apache.shiro</groupId> <artifac ...
- springMVC集成 -- shiro(配置)
备注:文中配置基本来自尚硅谷视频教程,也可自行参照shiro官方教程:http://shiro.apache.org/spring.html 1.首先通过maven导入shiro相关依赖jar包,修改 ...
- 【实用小技巧】spring springmvc集成shiro时报 No bean named 'shiroFilter' available
查了网上的,很多情况,不同的解决办法,总归一点就是配置文件加载的问题. 先看下配置文件中的配置 web.xml中的主要配置(这是修改后不在报错的:仅仅修改了一个位置:[classpath:spring ...
- springmvc集成shiro后,session、request是否发生变化
1. 疑问 我们在项目中使用了spring mvc作为MVC框架,shiro作为权限控制框架,在使用过程中慢慢地产生了下面几个疑惑,本篇文章将会带着疑问慢慢地解析shiro源码,从而解开心里面的那点小 ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
- Shiro+SpringMVC 实现更安全的登录(加密匹配&登录失败超次数锁定帐号)
原文:http://blog.csdn.net/wlwlwlwl015/article/details/48518003 前言 初学shiro,shiro提供了一系列安全相关的解决方案,根据官方的介绍 ...
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证
序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationCo ...
- springmvc简单集成shiro
前言: 有天和同事聊天, 谈起权限管理, 他说他有个同事用shiro用的很溜. 正好现在有个管理平台项目, 有权限控制的需求, 因此想借此机会研究一番. 本文主要简单讲解一下对shiro的一些认识, ...
随机推荐
- System.Drawing.Image在Save之后Type变了
前段时间发现asp.net MVC 3附带了一个相当方便的图片处理类WebImage,常用的图片处理功能全都包括进去了,用起来是相当的爽. 在项目中刚好有相关的图片处理需求,但由于实际项目是使用asp ...
- 清理DBA_DATAPUMP_JOBS中的孤立数据泵作业
今天在重构数据库时(将表空间中的表.索引转移到其它表空间)时,发现有两个奇怪的对象SYS_EXPORT_FULL_01.SYS_EXPORT_FULL_02搜索了一下,发现这个可能是EXPDP导出异常 ...
- Bug #19528825 "UNABLE TO PURGE A RECORD"
概述: 在生产环境中,当开启insert buffer时(参数innodb_change_buffering=all),部分实例偶尔会出现“UNABLE TO PURGE A RECORD”错误.这个 ...
- Javascript之旅——第五站:说说那些所谓的包装类型
最近不看犀牛书了,那本翻译的特烂而且好拗口,尤其是原型那块说的乱七八糟,后来经同事介绍,买了本js高级程序设计,然后就继续 苦逼的看,不吐槽了,继续说说js中有新鲜感的包装类型. 一:String 说 ...
- EF Power Tools 数据库逆向生成时T4模板修改
VS2013上使用EF Power Tools的Reverse Engineer Code First逆向生成. 发现数据库中的decimal(18, 4)字段在生成的mapping类中没有精度和小数 ...
- Ambari工具之认识学习01
随着大数据的越发流行,大大小小的互联网公司都开始参与一些大数据相关的业务,都想从中分一杯羹.Hadoop是大数据的典型代表,也可以说现在的领头大哥,很多互联网巨头都在使用hadoop,包括BAT等大公 ...
- QT学习第2天
回顾: 1.构建一个QT工程步骤 (1)qmake -project (2)qmake (3)make 2.两个常用的组件 QLabel 标签 QPushButton 按钮 --------- ...
- nodemanager execute container fail many times
ttempt_1448915696877_13139_m_000141_0 100.00 FAILED map > map px42pub:8042 logs Wed, 09 Dec 2015 ...
- 记录遇到的Python陷阱和注意点
最近使用Python的过程中遇到了一些坑,例如用datetime.datetime.now()这个可变对象作为函数的默认参数,模块循环依赖等等. 在此记录一下,方便以后查询和补充. 避免可变对象作为默 ...
- 开发Eclipse自定义控件
摘自:http://www.ibm.com/developerworks/cn/opensource/os-eclipcntl/ 我们在开发自定义控件时主要考虑以下问题: 1. 自定义控件的绘制:通常 ...