上篇将ssm框架整合完毕,这里剩下最后一步整合shiro权限框架,其实权限拦截比较简单,我比较偏向于自己去写filter和servlet去完成权限的分配,因为能用一个类解决的问题就不要用一个jar包解决。不过可以先理解shiro的思想,然后自己去写类进行拦截,其实权限控制一个filter类加一个servlet就可以完成,完全不需要一个shiro,大家可以试试,后续会上传我写的权限控制类
第一步:导入shiro的jar包
<!--Shiro Start-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--缓存-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
</dependency>
<!--Shiro End-->
shiro的版本用的是,看图
第二步:整合spring和shiro
1. 新建一个spring-shiro.xml文件,内容如下
关于shiro的内容这里就不多讲了,后续也会陆续上线shiro部分的博文,我这里有shiro的完整教学视频,需要的留下邮箱,我会发过去,免费,如果收费请拒绝支付,然后留言联系博主,谢谢。
<?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">
<!--Shiro 配置-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"></property>
<!-- 必须放在realms的前面配置,否则realms不生效 -->
<property name="authenticator" ref="authenticator"></property>
<property name="realms">
<list>
<ref bean="myRealm"/>
<ref bean="myRealm2"/>
</list>
</property>
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<!-- <property name="cacheManager" ref="ehCacheManager"></property> -->
<property name="cacheManagerConfigFile" value="classpath:config/ehcache.xml"/>
</bean>
<bean id="myRealm" class="xin.sunzy.ssms.realm.MyRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value="1024"></property>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
</property>
</bean>
<bean id="myRealm2" class="xin.sunzy.ssms.realm.MyRealm2">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA1"></property>
<property name="hashIterations" value="1024"/>
</bean>
</property>
</bean>
<!-- 可以自定义调用配置在spring ioc容器中的shirobean的生命周期方法 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
<!-- 在配置了生命周期lifecycleBeanPostProcessor,之后才可以使注解生效 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
<!-- 认证策略 -->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
</property>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<property name="loginUrl" value="/login.jsp"></property>
<property name="successUrl" value="/list.jsp"></property>
<property name="unauthorizedUrl" value="/unauthorized.jsp"></property>
<property name="filterChainDefinitionMap" ref="filterChainDefinitionsMap"/>
</bean>
<bean id="filterChainDefinitionsMapBuilder" class="xin.sunzy.ssms.realm.FilterChainDefinitionsMapBuilder"></bean>
<bean id="filterChainDefinitionsMap" factory-bean="filterChainDefinitionsMapBuilder" factory-method="filterChainDefinitionsMap"></bean>
</beans>
然后在web.xml文件中添加shiroFilter
<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>
注意配置filter-name一定要和spring中shiro bean的ID保持一致,否则会找不到实例报错,我这里都是用的shiroFilter。
然后新建一个realm类,我这里建了两个realm类是为了测试验证策略
package xin.sunzy.ssms.realm;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import xin.sunzy.ssms.entity.po.Permission;
import xin.sunzy.ssms.entity.po.Role;
import xin.sunzy.ssms.entity.po.User;
import xin.sunzy.ssms.service.intf.IUserService;
public class MyRealm extends AuthorizingRealm {
private final Logger logger = LoggerFactory.getLogger(MyRealm.class);
@Autowired
private IUserService userService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException {
System.out.println("MyRealm doGetAuthenticationInfo ********");
//从token中获取username
String username = ((UsernamePasswordToken)token).getUsername();
try {
//从数据库中获取实体
User user = userService.findByUsername(username);
if(user==null){
throw new AuthenticationException("MyRealm 未知的用户异常。。。");
}
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()),getName());
return authenticationInfo;
} catch (Exception e) {
logger.error("数据库操作异常");
return null;
}
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("MyRealm ,开始授权,doGetAuthorizationInfo**********");
User user = (User) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
for(Role role : user.getRoleList()){
authorizationInfo.addRole(role.getRoleName());
for (Permission p : role.getPermissionList()){
authorizationInfo.addStringPermission(p.getPermission());
authorizationInfo.addStringPermission(p.getOpsUrl());
}
}
return authorizationInfo;
}
}
这个MyRealm2没有任何用处,大家可以在里面写自己的认证逻辑
package xin.sunzy.ssms.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.realm.AuthenticatingRealm;
public class MyRealm2 extends AuthenticatingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("MyRealm2 doGetAuthenticationInfo *********");
return null;
}
}
然后就是FilterChainDefinitionsMapBuilder,实例工厂方法类,在spring-shiro.xml文件中用到了的,用来创建拦截链的map,我这里只是静态的拦截,这里需要从数据库中读取拦截链然后添加到map中。
package xin.sunzy.ssms.realm;
import org.springframework.beans.factory.annotation.Autowired;
import xin.sunzy.ssms.entity.po.User;
import xin.sunzy.ssms.service.intf.IUserService;
import java.util.LinkedHashMap;
public class FilterChainDefinitionsMapBuilder {
private static final String ANON = "anon";
private static final String AUTHC = "authc";
private static final String LOGOUT = "logout";
private static final String USER = "user";
@Autowired
private IUserService userService;
LinkedHashMap<String,Object> filterChainDefinitionsMap() throws Exception {
User user = userService.findByUsername("sunzy");
LinkedHashMap<String,Object> map = new LinkedHashMap<>();
map.put("/favicon.ico",ANON);
map.put("/login.jsp",ANON);
map.put("/login",ANON);
map.put("/toLogin",ANON);
map.put("/logout",LOGOUT);
map.put("/valid",ANON);
map.put("/**",AUTHC);
return map;
}
}
在classpath/config下新建一个ehcache.xml缓存配置文件
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"/>
</ehcache>
到此,shiro也就整合完成了
源码地址:http://git.oschina.net/sunknightzy/ssms