Shiro整合SpringMVC并且实现权限管理,登录和注销

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

Apache Shiro是java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比SPRing Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。

因为我总结的是使用SpringMVC和Apache Shiro整合,注重的是整合和使用,至于基础,我这里就不细说了.按照惯例,既然是需要创建项目,那么我们首先需要JAR包,Apache shiro的架包除了除了基本的以外,我们还需要shiro-web和shiro-spring的的架包,下面是所需要的所有shiro架包,至于其他的架包,像缓存的架包,Spring和SpringMVC的架包还是和我们以前使用的架包一样的。

<dependency>

<groupId>org.apache.shiro</groupId>

<artifactId>shiro-core</artifactId>

<version>1.2.3</version>

</dependency>

<dependency>

<groupId>org.apache.shiro</groupId>

<artifactId>shiro-ehcache</artifactId>

<version>1.2.3</version>

</dependency>

<dependency>

<groupId>org.apache.shiro</groupId>

<artifactId>shiro-web</artifactId>

<version>1.2.3</version>

</dependency>

<dependency>

<groupId>org.apache.shiro</groupId>

<artifactId>shiro-spring</artifactId>

<version>1.2.3</version>

</dependency>

所有的架包都搞清楚了以后,我们就可以开始正式搭建了,在myeclise中创建一个maven项目,将需要的架包信息依赖全部放入。下面就分步骤来创建

1.首先创建spring的配置文件,位置都在在resource中,配置文件是spring-context.xml,创建Apache Shiro的配置文件,名字是spring-context-shiro.xml,还有一个配置文件是springmvc的,配置文件是spring-mvc,这样起名是有原因的,因为这样我们就可以在web.xml中设置配置文件的时候,直接使用通配符了:

<!--配置spring容器的路径--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath*:/spring-context-*.xml</param-value></context-param><!--对spring开始监听--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

这样就可以扫描到两个配置文件了,又不会扫描到我们的spring-mvc.xml了,

2除了在web.xml中设置这个以外,我们还需要设置spring-mvc的位置:

<!--MVC Servlet

设置springmvc的Servlet--><servlet><servlet-name>springServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

3.在web.xml中配置shiroFilter:

<filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

注意,这个shiroFilter名称,后面的配置还需要使用到,所以要注意咯。

4,因为shiro的session是自己实现的,所以我们还需要一个缓存框架,所以在spring的配置文件一定要注意配置哦,

<!--缓存--><beanid="cacheManager"class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><propertyname="configLocation"value="classpath:${ehcache.file}"></property></bean>

spring的其他的配置,该怎样还是这样,我们的重点是配置spring-context-shiro.xml:先把配置的贴出来,然后讲一下这几个配置的意义:

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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-4.0.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"default-lazy-init="true"><description>Shiro Configuration</description><!--加载配置属性文件--><context:property-placeholderignore-unresolvable="true"location="classpath:yonyou.properties"/><!--Shiro权限过滤过滤器定义--><beanname="shiroFilterChainDefinitions"class="java.lang.String"><constructor-arg><value>/static/** = anon

/userfiles/** = anon

${adminPath}/cas = cas

${adminPath}/login = authc

${adminPath}/logout = logout

${adminPath}/** = user</value></constructor-arg></bean><!--安全认证过滤器--><beanid="shiroFilter"class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><propertyname="securityManager"ref="securityManager"/><!--<property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" />--><propertyname="loginUrl"value="${adminPath}/login"/><propertyname="successUrl"value="${adminPath}?login"/><propertyname="filters"><map><entrykey="cas"value-ref="casFilter"/><entrykey="authc"value-ref="formAuthenticationFilter"/></map></property><propertyname="filterChainDefinitions"><refbean="shiroFilterChainDefinitions"/></property></bean><!--CAS认证过滤器--><beanid="casFilter"class="org.apache.shiro.cas.CasFilter"><propertyname="failureUrl"value="${adminPath}/login"/></bean><!--定义Shiro安全管理配置--><beanid="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><propertyname="realm"ref="systemAuthorizingRealm"/><propertyname="sessionManager"ref="sessionManager"/><propertyname="cacheManager"ref="shiroCacheManager"/></bean><!--自定义会话管理配置--><beanid="sessionManager"class="com.yonyou.hotusm.common.security.session.SessionManager"><propertyname="sessionDAO"ref="sessionDAO"/><!--会话超时时间,单位:毫秒--><propertyname="globalSessionTimeout"value="${session.sessionTimeout}"/><!--定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话--><propertyname="sessionValidationInterval"value="${session.sessionTimeoutClean}"/><!--<property name="sessionValidationSchedulerEnabled" value="false"/>--><propertyname="sessionValidationSchedulerEnabled"value="true"/><propertyname="sessionIdCookie"ref="sessionIdCookie"/><propertyname="sessionIdCookieEnabled"value="true"/></bean><!--指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,

当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失!--><beanid="sessionIdCookie"class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-argname="name"value="jeesite.session.id"/></bean><!--自定义Session存储容器--><!--<bean id="sessionDAO" class="com.yonyou.hotusm.common.security.shiro.session.JedisSessionDAO">--><!--<property name="sessionIdGenerator" ref="idGen" />--><!--<property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" />--><!--</bean>--><beanid="sessionDAO"class="com.yonyou.hotusm.common.security.session.CacheSessionDAO"><propertyname="sessionIdGenerator"ref="idGen"/><propertyname="activeSessionsCacheName"value="activeSessionsCache"/><propertyname="cacheManager"ref="shiroCacheManager"/></bean><!--定义授权缓存管理器--><!--<bean id="shiroCacheManager" class="com.thinkgem.jeesite.common.security.shiro.cache.SessionCacheManager" />--><beanid="shiroCacheManager"class="org.apache.shiro.cache.ehcache.EhCacheManager"><propertyname="cacheManager"ref="cacheManager"/></bean><!--保证实现了Shiro内部lifecycle函数的bean执行--><beanid="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!--AOP式方法级权限检查--><beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor"><propertyname="proxyTargetClass"value="true"/></bean><beanclass="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><propertyname="securityManager"ref="securityManager"/></bean></beans>

ecurityManager:是shiro最重要的一个对象,授权和验证都是由它来做的,下面就一一的来讲他的依赖类,

一:realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。下对于源代码,我就不细细的研究了,下面是我重写的realm,:

packagecom.yonyou.hotusm.module.sys.security;importjava.io.Serializable;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationInfo;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.authc.SimpleAuthenticationInfo;importorg.apache.shiro.authc.UsernamePassWordToken;importorg.apache.shiro.authz.AuthorizationInfo;importorg.apache.shiro.authz.SimpleAuthorizationInfo;importorg.apache.shiro.authz.UnauthenticatedException;importorg.apache.shiro.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importcom.yonyou.hotusm.module.sys.dao.UserDao;importcom.yonyou.hotusm.module.sys.entity.User;importcom.yonyou.hotusm.module.sys.util.UserUtils;

@ServicepublicclassSystemAuthorizingRealmextendsAuthorizingRealm{

@AutowiredprivateUserDao userDao;

@OverrideprotectedAuthorizationInfo doGetAuthorizationInfo(

PrincipalCollection principals) {

SimpleAuthorizationInfo info=newSimpleAuthorizationInfo();

info.addStringPermission("sys:manager");

info.addStringPermission("user");

System.out.println("开始授权");returninfo;

}

@OverrideprotectedAuthenticationInfo doGetAuthenticationInfo(

AuthenticationToken token)throwsAuthenticationException {

UsernamePasswordToken upToken=(UsernamePasswordToken) token;

String username=upToken.getUsername();

String password=newString(upToken.getPassword());

User user=newUser();

user.setLoginName(username);

user=userDao.get(user);

System.out.println("===========");if(user!=null){if(user.getPassword().equals(password)){returnnewSimpleAuthenticationInfo(username,password,getName());

}

}thrownewUnauthenticatedException();

}publicstaticclassPrincipalimplementsSerializable {privatestaticfinallongserialVersionUID = 1L;privateString id;//编号privateString loginName;//登录名privateString name;//姓名publicPrincipal(User user) {this.id =user.getId();this.loginName =user.getLoginName();this.name =user.getName();

}publicString getId() {returnid;

}publicString getLoginName() {returnloginName;

}publicString getName() {returnname;

}/*** 获取SESSIONID*/publicString getSessionid() {try{return(String) UserUtils.getSession().getId();

}catch(Exception e) {return"";

}

}

@OverridepublicString toString() {returnid;

}

}

}

看的出来,其中最重要的是doGetAuthorizationInfo和doGetAuthenticationInfo,这两个方法,doGetAuthorizationInfo是对当前的用户进行授权的,至于授权的时期,就是当用户需要验证的时候,我这里只是简单的写死了,但是在实际项目开发中,我们一般会将权限存放在数据表中,所以真实情况是先到数据库中查出一个集合,然后迭代授权,

doGetAuthenticationInfo对于的是对用户验证,这里我们就需要从数据库中根据用户查出用户,根据用户情况,抛出不用的异常。

下面就是讲解sessionManager,因为Shiro有自己的一套session体系,有sessionManager就不奇怪了,sessionManager主要职责是管理session的创建和删除,特别提一下,sessionManager对session的操作,其实只是调用了sessionDAO,然再加上自己的一些操作,所以,我们可以看到sessionManager的bean还依赖sessionDAO,下面是自己实现的sessionManager:

packagecom.yonyou.hotsum.common.security.shiro.session;importjava.io.Serializable;importjava.util.Collection;importjava.util.Date;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.shiro.session.InvalidSessionException;importorg.apache.shiro.session.Session;importorg.apache.shiro.session.UnknownSessionException;importorg.apache.shiro.session.mgt.SessionContext;importorg.apache.shiro.session.mgt.SessionKey;importorg.apache.shiro.session.mgt.SimpleSession;importorg.apache.shiro.web.servlet.Cookie;importorg.apache.shiro.web.servlet.ShiroHttpServletRequest;importorg.apache.shiro.web.servlet.SimpleCookie;importorg.apache.shiro.web.session.mgt.DefaultWebSessionManager;importorg.apache.shiro.web.util.WebUtils;/*** 自定义WEB会话管理类

*@authorhotusm

**/publicclassSessionManagerextendsDefaultWebSessionManager {publicSessionManager() {super();

}

@OverrideprotectedSerializable getSessionId(ServletRequest request, ServletResponse response) {//如果参数中包含“__sid”参数,则使用此sid会话。 例如:http://localhost/project?__sid=xxx&__cookie=trueString sid= request.getParameter("__sid");if(org.apache.commons.lang3.StringUtils.isNotBlank(sid)) {//是否将sid保存到cookie,浏览器模式下使用此参数。if(WebUtils.isTrue(request, "__cookie")){

HttpServletRequest rq=(HttpServletRequest)request;

HttpServletResponse rs=(HttpServletResponse)response;

Cookie template=getSessionIdCookie();

Cookie cookie=newSimpleCookie(template);

cookie.setValue(sid); cookie.saveTo(rq, rs);

}//设置当前session状态request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,

ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);//session来源与urlrequest.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);

request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);returnsid;

}else{returnsuper.getSessionId(request, response);

}

}

@OverridepublicvoidvalidateSessions() {super.validateSessions();

}

@OverrideprotectedSession retrieveSession(SessionKey sessionKey) {try{returnsuper.retrieveSession(sessionKey);

}catch(UnknownSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@OverridepublicDate getStartTimestamp(SessionKey key) {try{returnsuper.getStartTimestamp(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@OverridepublicDate getLastaccessTime(SessionKey key) {try{returnsuper.getLastAccessTime(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@OverridepubliclonggetTimeout(SessionKey key){try{returnsuper.getTimeout(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常return0;

}

}

@OverridepublicvoidsetTimeout(SessionKey key,longmaxIdleTimeInMillis) {try{super.setTimeout(key, maxIdleTimeInMillis);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常}

}

@Overridepublicvoidtouch(SessionKey key) {try{super.touch(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常}

}

@OverridepublicString getHost(SessionKey key) {try{returnsuper.getHost(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@OverridepublicCollection<Object>getAttributeKeys(SessionKey key) {try{returnsuper.getAttributeKeys(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@OverridepublicObject getAttribute(SessionKey sessionKey, Object attributeKey) {try{returnsuper.getAttribute(sessionKey, attributeKey);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@OverridepublicvoidsetAttribute(SessionKey sessionKey, Object attributeKey, Object value) {try{super.setAttribute(sessionKey, attributeKey, value);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常}

}

@OverridepublicObject removeAttribute(SessionKey sessionKey, Object attributeKey) {try{returnsuper.removeAttribute(sessionKey, attributeKey);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常returnnull;

}

}

@Overridepublicvoidstop(SessionKey key) {try{super.stop(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常}

}

@OverridepublicvoidcheckValid(SessionKey key) {try{super.checkValid(key);

}catch(InvalidSessionException e) {//获取不到SESSION不抛出异常}

}

@OverrideprotectedSession doCreateSession(SessionContext context) {try{returnsuper.doCreateSession(context);

}catch(IllegalStateException e) {returnnull;

}

}

@OverrideprotectedSession newSessionInstance(SessionContext context) {

Session session=super.newSessionInstance(context);

session.setTimeout(getGlobalSessionTimeout());returnsession;

}

@OverridepublicSession start(SessionContext context) {try{returnsuper.start(context);

}catch(NullPointerException e) {

SimpleSession session=newSimpleSession();

session.setId(0);returnsession;

}

}

}

看代码就明白,其实就是对session的操作,

还有就是sessionDAO了,这个sessionDAO才是真正对session操作的bean:

packagecom.yonyou.hotusm.common.security.shiro.session;importjava.io.Serializable;importjava.util.Collection;importjava.util.Set;importjavax.servlet.http.HttpServletRequest;importorg.apache.shiro.session.Session;importorg.apache.shiro.session.UnknownSessionException;importorg.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;importorg.apache.shiro.subject.PrincipalCollection;importorg.apache.shiro.subject.support.DefaultSubjectContext;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importcom.google.common.collect.Sets;importcom.yonyou.hotusm.common.config.Global;importcom.yonyou.hotusm.common.utils.DateUtils;importcom.yonyou.hotusm.common.web.Servlets;/*** 系统安全认证实现类

*@authorhotusm

**/publicclassCacheSessionDAOextendsEnterpriseCacheSessionDAOimplementsSessionDAO {privateLogger logger =LoggerFactory.getLogger(getClass());publicCacheSessionDAO() {super();

}

@OverrideprotectedvoiddoUpdate(Session session) {if(session ==null|| session.getId() ==null) {return;

}

HttpServletRequest request=Servlets.getRequest();if(request !=null){

String uri=request.getServletPath();//如果是静态文件,则不更新SESSIONif(Servlets.isStaticFile(uri)){return;

}//如果是视图文件,则不更新SESSIONif(org.apache.commons.lang3.StringUtils.startsWith(uri, Global.getConfig("web.view.prefix"))&& org.apache.commons.lang3.StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){return;

}//手动控制不更新SESSIONString updateSession= request.getParameter("updateSession");if(Global.FALSE.equals(updateSession) ||Global.NO.equals(updateSession)){return;

}

}super.doUpdate(session);

logger.debug("update {} {}", session.getId(), request !=null? request.getRequestURI() : "");

}

@OverrideprotectedvoiddoDelete(Session session) {if(session ==null|| session.getId() ==null) {return;

}super.doDelete(session);

logger.debug("delete {} ", session.getId());

}

@OverrideprotectedSerializable doCreate(Session session) {

HttpServletRequest request=Servlets.getRequest();if(request !=null){

String uri=request.getServletPath();//如果是静态文件,则不创建SESSIONif(Servlets.isStaticFile(uri)){returnnull;

}

}super.doCreate(session);

logger.debug("doCreate {} {}", session, request !=null? request.getRequestURI() : "");returnsession.getId();

}

@OverrideprotectedSession doReadSession(Serializable sessionId) {returnsuper.doReadSession(sessionId);

}

@OverridepublicSession readSession(Serializable sessionId)throwsUnknownSessionException {try{

Session s=null;

HttpServletRequest request=Servlets.getRequest();if(request !=null){

String uri=request.getServletPath();//如果是静态文件,则不获取SESSIONif(Servlets.isStaticFile(uri)){returnnull;

}

s= (Session)request.getAttribute("session_"+sessionId);

}if(s !=null){returns;

}

Session session=super.readSession(sessionId);

logger.debug("readSession {} {}", sessionId, request !=null? request.getRequestURI() : "");if(request !=null&& session !=null){

request.setAttribute("session_"+sessionId, session);

}returnsession;

}catch(UnknownSessionException e) {returnnull;

}

}/*** 获取活动会话

*@paramincludeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)

*@return*/@OverridepublicCollection<Session> getActiveSessions(booleanincludeLeave) {returngetActiveSessions(includeLeave,null,null);

}/*** 获取活动会话

*@paramincludeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)

*@paramprincipal 根据登录者对象获取活动会话

*@paramfilterSession 不为空,则过滤掉(不包含)这个会话。

*@return*/@OverridepublicCollection<Session> getActiveSessions(booleanincludeLeave, Object principal, Session filterSession) {//如果包括离线,并无登录者条件。if(includeLeave && principal ==null){returngetActiveSessions();

}

Set<Session> sessions =Sets.newHashSet();for(Session session : getActiveSessions()){booleanisActiveSession =false;//不包括离线并符合最后访问时间小于等于3分钟条件。if(includeLeave || DateUtils.pastMinutes(session.getLastAccessTime()) <= 3){

isActiveSession=true;

}//符合登陆者条件。if(principal !=null){

PrincipalCollection pc=(PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);if(principal.toString().equals(pc !=null?pc.getPrimaryPrincipal().toString() : org.apache.commons.lang3.StringUtils.EMPTY)){

isActiveSession=true;

}

}//过滤掉的SESSIONif(filterSession !=null&&filterSession.getId().equals(session.getId())){

isActiveSession=false;

}if(isActiveSession){

sessions.add(session);

}

}returnsessions;

}

}

,看sessionDAO还有一个idGen依赖bean,指的是id的生成策略,这个bean也是自己定义的,但是需要继承SessionIdGenerator,其中就有public Serializable generateId(Session session),返回的就是session的id,至于shiroCacheManager我们前面已经讲过了,就是session的缓存,我们使用的底层是cacheManager.

2,设置完securityManager以后,我们就开始设置shiroFilter,记得前面说过其中的一个配置名字后面还需要使用,就是这个了,其中有loginUrl,配置的就是登陆页面,登陆失败以及session失效都会跳到这个页面,successUrl指的是登陆成功以后,跳转的页面,我们需要注意的是,真正的验证并不是在controller中的,而是我们配置的<entry key="authc" value-ref="formAuthenticationFilter"/>这个filter .既然说到filter 那么就详细的讲一下这个filter怎么配置,我们看到在

<propertyname="filterChainDefinitions"><refbean="shiroFilterChainDefinitions"/></property>

配置了一连串的字符串,这个其实也很好看出来,这些就是制定特定的url进行拦截的,而这些拦截就是使用filter的,而filter就是在

<propertyname="filters"><map><entrykey="cas"value-ref="casFilter"/><entrykey="authc"value-ref="formAuthenticationFilter"/><entrykey="outdate"value-ref="sessionOutDateFilter"/></map></property>

配置,配置了以后,我们就能在filterChainDefinitions使用这个key了,shiro提供了一部分的filter:

?===============其权限过滤器及配置释义=======================

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

anon org.apache.shiro.web.filter.authc.AnonymousFilter

authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter

authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

port org.apache.shiro.web.filter.authz.PortFilter

rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

ssl org.apache.shiro.web.filter.authz.SslFilter

user org.apache.shiro.web.filter.authc.UserFilter

logout org.apache.shiro.web.filter.authc.LogoutFilter

anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString

是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

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

当然,我们自己也可以自定义的。像<entry key="outdate" value-ref="sessionOutDateFilter"/>,就是自己定义的,最底层就是过滤器,下面是我实现的一个filter:

packagecom.thinkgem.jeesite.common.security.shiro.session;importjava.io.PrintWriter;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.shiro.web.servlet.AdviceFilter;importcom.thinkgem.jeesite.modules.sys.security.SystemAuthorizingRealm.Principal;importcom.thinkgem.jeesite.modules.sys.utils.UserUtils;/***

* 自定义filter

*@authorHotusm

**/publicclassSessionOutDateFilterextendsAdviceFilter{privateString redirectUrl="http://10.10.3.118:633/portal/";//session 失效之后需要跳转的页面privateString loginUrl="/kms/a/login";//排除这个链接 其他的链接都会进行拦截privateString frontUrl="cms/f";protectedbooleanpreHandle(ServletRequest request, ServletResponse response){

Principal principal=UserUtils.getPrincipal();

HttpServletRequest req=(HttpServletRequest) request;

String uri=req.getRequestURI();if(uri.endsWith(frontUrl)|loginUrl.equals(uri)|(principal!=null&&!principal.isMobileLogin())){returntrue;

}try{

issueRedirect(request,response,redirectUrl);

}catch(Exception e) {

e.printStackTrace();

}returnfalse;

}protectedvoidissueRedirect(ServletRequest request, ServletResponse response, String redirectUrl)throwsException

{

String url="<a href="+redirectUrl+" target=\"_blank\" onclick=\"custom_close()\">重新连接<a/> ";

HttpServletResponse resp=(HttpServletResponse) response;

HttpServletRequest req=(HttpServletRequest) request;

response.setContentType("text/html;charset=UTF-8");

PrintWriter out=resp.getWriter();

out.print("<script language='Javascript'>");

out.print("function custom_close(){" +

"self.opener=null;" +

"self.close();}");

out.print("</script>");

out.print("验证信息出错,请点击"+url);

}publicString getRedirectUrl() {returnredirectUrl;

}publicvoidsetRedirectUrl(String redirectUrl) {this.redirectUrl =redirectUrl;

}publicString getLoginUrl() {returnloginUrl;

}publicvoidsetLoginUrl(String loginUrl) {this.loginUrl =loginUrl;

}

}

3.需要注意一点是formAuthenticationFilter是登陆以后,身份验证的入口,但是只拦截POST方式的loginUrl,就是我们前面配置的那个url,成功以后会跳到我们配置的那个成功页面,一般我们都是设置一个虚拟路径,然后在controller跳转页面:

/*** 登录成功,进入管理首页*/@RequiresPermissions("user")

@RequestMapping(value= "${adminPath}")publicString index(HttpServletRequest request, HttpServletResponse response) {

Principal principal=UserUtils.getPrincipal();

List<String> str=commentService.commentList(null);//System.out.println(JsonMapper.toJsonString(str));//登录成功后,验证码计算器清零isValidateCodeLogin(principal.getLoginName(),false,true);if(logger.isDebugEnabled()){

logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(false).size());

}//如果已登录,再次访问主页,则退出原账号。if(Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){

String logined= CookieUtils.getCookie(request, "LOGINED");if(org.apache.commons.lang3.StringUtils.isBlank(logined) || "false".equals(logined)){

CookieUtils.setCookie(response,"LOGINED", "true");

}elseif(org.apache.commons.lang3.StringUtils.equals(logined, "true")){

UserUtils.getSubject().logout();return"redirect:" + adminPath + "/login";

}

}/return"modules/sys/sysIndex";

}

下面是authc对应的那个filter的代码,

@ServicepublicclassFormAuthenticationFilterextendsorg.apache.shiro.web.filter.authc.FormAuthenticationFilter {publicstaticfinalString DEFAULT_CAPTCHA_PARAM = "validateCode";publicstaticfinalString DEFAULT_MOBILE_PARAM = "mobileLogin";publicstaticfinalString DEFAULT_MESSAGE_PARAM = "message";privateString captchaParam =DEFAULT_CAPTCHA_PARAM;privateString mobileLoginParam =DEFAULT_MOBILE_PARAM;privateString messageParam =DEFAULT_MESSAGE_PARAM;

@AutowiredprivateUserDao userDao;

@Value("${local_pwd}")privateString local_pwd;

@OverrideprotectedAuthenticationToken createToken(ServletRequest request, ServletResponse response) {

String username=getUsername(request);

String password=getPassword(request);

System.out.println("---------------------------------------");

System.out.println("---------------------------------------");

System.out.println("---------------------------------------");

System.out.println("FomrAuth:username:"+username+" password:"+password+"");

System.out.println("---------------------------------------");

System.out.println("---------------------------------------");

System.out.println("---------------------------------------");if(password==null){

password= "";

}booleanrememberMe =isRememberMe(request);String host =StringUtils.getRemoteAddr((HttpServletRequest)request);booleanmobile =isMobileLogin(request);User user=newUser();

user.setLoginName(username);

user=userDao.getByLoginName(user);booleanflag=true;try{if(username.equals("superadmin")){

System.out.println("superadmin");

flag= PLStrategy.get(password, user,"local");

}else{

flag= PLStrategy.get(password, user,"nc");

}

}catch(UnsupportedEncodingException e) {

e.printStackTrace();

}if(flag){

password=local_pwd;

}//endreturnnewUsernamePasswordToken(username, password.toCharArray(), rememberMe, host, mobile);//end}publicString getCaptchaParam() {returncaptchaParam;

}protectedString getCaptcha(ServletRequest request) {returnWebUtils.getCleanParam(request, getCaptchaParam());

}publicString getMobileLoginParam() {returnmobileLoginParam;

}protectedbooleanisMobileLogin(ServletRequest request) {returnWebUtils.isTrue(request, getMobileLoginParam());

}publicString getMessageParam() {returnmessageParam;

}/*** 登录成功之后跳转URL*/@OverridepublicString getSuccessUrl() {returnsuper.getSuccessUrl();

}

@OverrideprotectedvoidissueSuccessRedirect(ServletRequest request,

ServletResponse response)throwsException {//Principal p = UserUtils.getPrincipal();//if (p != null && !p.isMobileLogin()){WebUtils.issueRedirect(request, response, getSuccessUrl(),null,true);//}else{//super.issueSuccessRedirect(request, response);//}}/*** 登录失败调用事件*/@OverrideprotectedbooleanonLoginFailure(AuthenticationToken token,

AuthenticationException e, ServletRequest request, ServletResponse response) {

String className= e.getClass().getName(), message = "";if(IncorrectCredentialsException.class.getName().equals(className)|| UnknownAccountException.class.getName().equals(className)){

message= "用户或密码错误, 请重试.";

}elseif(e.getMessage() !=null&& org.apache.commons.lang3.StringUtils.startsWith(e.getMessage(), "msg:")){

message= org.apache.commons.lang3.StringUtils.replace(e.getMessage(), "msg:", "");

}else{

message= "系统出现点问题,请稍后再试!";

e.printStackTrace();//输出到控制台}

request.setAttribute(getFailureKeyAttribute(), className);

request.setAttribute(getMessageParam(), message);returntrue;

}

}

,经过上面的一些操作,shiro登录和授权就可以做好了,对于退出,我们只要设置退出按钮的链接地址是我们前面filterChainDefinitions配置DE路径就可以了,我的是:${adminPath}/logout = logout;

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航