springmvc集成shiro登录权限示例代码
程序员文章站
2024-03-07 16:46:15
一般的登录流程会有:用户名不存在,密码错误,验证码错误等..
在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理。
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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 安卓(Android)实现选择时间功能
下一篇: Android简单获取经纬度的方法