【Apach shiro】spring 整合Apache shiro
1、新建application-shiro.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="shiroConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:/shiro/shiro.properties"/> <property name="ignoreUnresolvablePlaceholders" value="true"/> </bean> <!-- 整合shiro --> <!-- 自定义Realm --> <bean id="myRealm" class="com.smile.azxx.shiro.MyRealm"> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="${shiro.activeRealm}" /> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- Shiro过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- Shiro的核心安全接口,这个属性是必须的 --> <property name="securityManager" ref="securityManager"/> <!-- 身份认证失败,则跳转到登录页面的配置 --> <property name="loginUrl" value="/pages/login.jsp"/> <!-- 权限认证失败,则跳转到指定页面 --> <property name="unauthorizedUrl" value="/unauthor.jsp"/> <!--<property name="filters">--> <!--<map>--> <!--<entry key="authc" value-ref="shiro" />--> <!--<entry key="sysUser" value-ref="sysUserFilter" />--> <!--<entry key="kickout" value-ref="kickoutFilter"/>--> <!--</map>--> <!--</property>--> <!-- Shiro连接约束配置,即过滤链的定义 --> <property name="filterChainDefinitionMap" ref="shiroFilterChainDefinitionsMap"/> <!-- Shiro连接约束配置,即过滤链的定义 --> <!--<property name="filterChainDefinitions">--> <!--<value>--> <!--/login=anon--> <!--/static/**=anon--> <!--/scripts/**=anon--> <!--/**=authc--> <!--</value>--> <!--</property>--> </bean> <!--Shiro filter url configs --> <bean id="shiroFilterChainDefinitionsMap" class="com.smile.azxx.shiro.ShiroFilterChainDefinitionsMap"/> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 开启Shiro注解 --> <!--<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"--> <!--depends-on="lifecycleBeanPostProcessor"/>--> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- 用户授权信息Cache --> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <!-- 如果要实现cas的remember me的功能,需要用到下面这个bean,并设置到securityManager的subjectFactory中 --> <!--<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>--> <!-- 基于Form表单的身份验证过滤器 --> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="usernameParam" value="username" /> <property name="passwordParam" value="password" /> <property name="rememberMeParam" value="rememberMe" /> <property name="loginUrl" value="/login" /> </bean> <!-- 自定义拦截器 --> <!--<bean id="sysUserFilter" class="com.smile.azxx.shiro.SysUserFilter"></bean>--> <!--<bean id="shiro" class="com.smile.azxx.shiro.ShiroFilter"/>--> <!--<bean id="kickoutFilter" class="com.myweb.spring.KickoutSessionControlFilter">--> <!--<property name="kickoutUrl" value="/api/user/login"/>--> <!--<property name="SessionManager" ref="sessionManager"/>--> <!--<property name="cacheManager" ref="cacheManager"/>--> <!--<property name="kickoutAfter" value="false"/>--> <!--<property name="maxSession" value="2"/>--> <!--</bean>--> </beans>
#shiro.properties
shiro.activeRealm = myRealm /static/**=anon /scripts/**=anon /getVerifyImage=anon /login=anon /logout=logout #/**=authc
2、在web.xml 添加配置
<!-- shiro过滤器定义 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 --> <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>
3、创建 MyRealm 类
package com.smile.azxx.shiro; import com.smile.azxx.entity.sysmng.User; import com.smile.azxx.service.sysmng.UserService; import org.apache.commons.lang.StringUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationException; 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.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.hibernate.service.spi.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; import java.util.Set; /** * Created by smile on 2018/4/6. */ public class MyRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private UserService userService; /** * 为当前登陆成功的用户授予权限和角色,已经登陆成功了 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 根据用户配置用户与权限 if (principals == null) { throw new AuthorizationException("PrincipalCollection method argument cannot be null."); } String username = (String) principals.getPrimaryPrincipal(); //获取用户名 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); List<String> roles = userService.getRoles(username); if(roles!=null&&roles.size()>0){ authorizationInfo.setRoles((Set<String>) roles); authorizationInfo.setStringPermissions((Set<String>) userService.getResource(roles)); } return authorizationInfo; } /** * 认证回调函数,登录时调用. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String userName = token.getUsername(); logger.info("请求用户名:"+userName); // 清空权限缓存,保证每次登陆都重新同步缓存至最新 SimplePrincipalCollection key = null; Cache<Object, AuthorizationInfo> cache = super.getAuthorizationCache(); for (Object k : cache.keys()) { if (k.toString().equals(userName)) { key = (SimplePrincipalCollection) k; break; } } if (key != null) { cache.remove(key); } // logger.info("doGetAuthenticationInfoAuthenticationToken............username=" + userName); if (userName != null && !"".equals(userName)){ User user = null; try { user = userService.getUserByName(userName); logger.info("username=" + userName + ";load=" + (user == null ? "false" : "true")); } catch (ServiceException e) { e.printStackTrace(); } if(user!=null && StringUtils.isNotBlank(user.getUsername())){ SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),getName()); SecurityUtils.getSubject().getSession() .setAttribute("c_user", user); return authenticationInfo; }else { throw new UnknownAccountException("该账号未注册,请尝试其他账号!"); } } return null; } }