English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Обычный процесс входа включает: не существует имени пользователя, пароль неверный, код ошибки и т.д.
После интеграции 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 |
Конфигурация shiro в web.xml
<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>
Создание一个新的 конфигурации shiro-context-shiro.xml для широ-related информации, использование 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" /> <!-- АОП-образный метод проверки прав доступа на уровне методов --> <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; импортировать 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; импортировать java.util.Map; импортировать javax.annotation.PostConstruct; импортировать com.chunhui.webservice.common.utils.EmployeeType; импортировать com.chunhui.webservice.common.utils.VertifyStatus; импортировать org.apache.commons.lang3.StringUtils; импортировать org.apache.shiro.SecurityUtils; импортировать org.apache.shiro.authc.*; импортировать org.apache.shiro.authc.credential.HashedCredentialsMatcher; импортировать org.apache.shiro.authz.AuthorizationInfo; импортировать org.apache.shiro.authz.SimpleAuthorizationInfo; импортировать org.apache.shiro.cache.Cache; импортировать org.apache.shiro.realm.AuthorizingRealm; импортировать org.apache.shiro.session.Session; импортировать org.apache.shiro.subject.PrincipalCollection; импортировать org.apache.shiro.subject.SimplePrincipalCollection; импортировать org.apache.shiro.subject.Subject; импортировать org.springframework.context.annotation.DependsOn; импортировать org.springframework.stereotype.Service; импортировать com.chunhui.webservice.common.servlet.ValidateCodeServlet; импортировать 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.setTimeout(60000); String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE); если (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; } 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>
Вот и все, что было в этой статье, мы надеемся, что это поможет вам в изучении, и希望大家多多支持呐喊教程。
Заявление: содержание этой статьи взято из Интернета, авторские права принадлежат их законным владельцам, материалы предоставлены пользователями Интернета, сайт не обладает правами собственности, материалы не были отредактированы вручную, и сайт не несет ответственности за связанные с этим юридические последствия. Если вы обнаружите материалы,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма замените # на @) для подачи жалобы,并提供相关证据. Если будет установлено, что материалы являются подозрительными, сайт немедленно удалил涉嫌侵权的内容.