English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Le processus de connexion typique inclut : le nom d'utilisateur inexistant, le mot de passe incorrect, l'erreur de captcha, etc.
Après l'intégration de Shiro, les permissions d'accès externes de l'application et le contrôle d'accès sont confiés à Shiro pour la gestion.
Shiro offre deux fonctionnalités principales : l'authentification (Authentication) et l'autorisation (Authorization); l'authentification a pour rôle de prouver que l'on peut accéder, généralement par le nom d'utilisateur et le mot de passe, tandis que l'autorisation détermine qui peut accéder à quels ressources, contrôlé par le système de rôles et de permissions utilisateur personnalisé du développeur.
La gestion de session et la gestion de cache de Shiro ne sont pas dans le cadre de cet article.
La présente section décrit l'intégration de Spring MVC et Shiro à travers le processus de traitement de l'échec de la connexion.
Dépendances du projet :
Nom de la dépendance | version |
spring | 4.1.4.RELEASE |
shiro | 1.2.2 |
self4j | 1.7.5 |
log4j | 1.2.17 |
Configurez shiro dans 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>
Créez un nouveau spring-context-Configurer shiro.xml pour les informations shiro, charger avec 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>Configuration de Shiro</description> <!-- Filtre d'authentification et d'autorisation --> <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> <!--Personnalisez le filtre de validation de connexion--> <entry key="authc" value-ref="formAuthenticationFilter" /> </map> </property> <property name="filterChainDefinitions"> <value> /sys/login = authc /sys/logout = logout /sys/** = user </value> </property> </bean> <!-- définir les principaux objets d'affaires de Shiro --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="systemAuthorizingRealm" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- le générateur d'ID de session --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator">/> <!-- le gestionnaire de session, définir l'expiration de session et la sauvegarde --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- Le temps d'expiration global de la session (en millisecondes), par défaut30 minutes --> <property name="globalSessionTimeout" value="1800000" /> <property name="sessionDAO" ref="sessionDAO"/> </bean> <!-- le gestionnaire de validation de session, chaque3chaque minute, la vérification est exécutée --> <!-- <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> <!-- Le sessionDAO conserve les informations d'authentification --> <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 d'informations d'autorisation de l'utilisateur, utilisant EhCache --> <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- Gestionnaire de cycle de vie de Shiro --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- Vérification des permissions au niveau de la méthode par 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>
Créer un filtre d'authentification de connexion 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; /** * Classe de filtrage de validation de formulaire (comprendant la validation du captcha)*/ @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); } }
Nouveau jeton de classe UsernamePasswordToken.java
package com.chunhui.webservice.modules.sys.security; /** * Classe de jeton de mot de passe et d'utilisateur (y compris le code de vérification)*/ 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; } }
Le dernier est la classe d'implémentation d'authentification 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; /** * Classe d'implémentation de l'authentification système*/ @Service @DependsOn({ "employeeDao", "roleDao", "menuDao" }) public class SystemAuthorizingRealm extends AuthorizingRealm { private SystemService systemService; /** * Fonction de rappel d'authentification, appelée lors de la connexion */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; // Juger le code de validation Session session = SecurityUtils.getSubject().getSession(); // Définir un temps d'expiration de session indépendant pour la session session.setTimeout();60000); String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE); if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)) { throw new CaptchaException("Erreur de captcha !"); } //Si le compte n'existe pas, afficher //throw new UnknownAccountException(); //Si le compte est désactivé, afficher //throw new DisabledAccountException(); //Enregistrer la langue sélectionnée lors de la connexion 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(); } }/** * Fonction de rappel de consultation d'autorisation, appelée lorsque l'information d'autorisation de l'utilisateur n'est pas dans le cache */ @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; } /** * Informations d'autorisation de l'utilisateur */ 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; } } }
Alors, dans la page JSP, il est possible d'obtenir le type d'exception spécifique de l'exception de connexion pour afficher la cause de l'erreur sur la page.
<%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(在发送邮件时,请将#替换为@进行举报,并提供相关证据。一经查实,本站将立即删除涉嫌侵权内容。)