一、SSM整合shiro框架
1.步骤
1.添加shiro框架需要的jar包,包括shiro-core、shiro-web、shiro-spring的关系依赖
<!-- shiro jar包依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</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-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
2.在web.xml文件中配置shiro的过滤器
<!-- 配置shiro框架的过滤器 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 设置true由servlet容器控制filter的生命周期 -->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 添加字符集过滤器 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.添加applicationContext.shiro.xml文件,添加在web.xml中filter对应的spring容器对应的bean
4.静态资源处理
<!-- web.xml中shiro的filter对应的bean -->
<!-- Shiro 的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
<property name="loginUrl" value="/login.do" />
<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
<property name="successUrl" value="/index.do" />
<!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->
<property name="unauthorizedUrl" value="/nofunc.jsp" />
<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
<property name="filterChainDefinitions">
<value>
<!-- 对静态资源设置匿名访问 -->
/static/* = anon
/login.do = anon
/toLogin.do=anon
<!-- 过滤器对资源进行验证 -->
/index.do = authc
<!-- 请求 logout地址,shiro去清除session -->
/logout.do = logout
<!-- 具有指定的权限才能访问 -->
/userManager.do = perms[user:manager]
/roleManager.do = perms[role:manager]
/toUserRole.do = perms[user:pression]
<!-- /* = authc 所有url都必须认证通过才可以访问 -->
/* = authc
</value>
</property>
</bean>
<!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="authenRealm" />
</bean>
<!-- realm -->
<bean id="authenRealm" class="com.demo.realm.AuthenRealms">
<!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="1" />
</bean>
5.自定义AuthenRalms
public class AuthenRealms extends AuthorizingRealm {
@Resource
IUserService userService;
@Resource
IFunctionService functionService;
/**
* 授权方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取当前用户信息
User user = (User)principals.getPrimaryPrincipal();
List<String> perms = new ArrayList<String>();
//List<String> roles = new ArrayList<String>();
//根据用户信息获取所属于角色
//根据角色查权限
List<Function> functions = functionService.findByUserId(user.getUserId());
for(Function func : functions){
perms.add(func.getFuncCode());
}
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//把所有的权限串列表都放到SimpleAuthorizationInfo对象中
authorizationInfo.addStringPermissions(perms);
//authorizationInfo.addRoles(roles);//放置所有的角色信息
return authorizationInfo;
}
/**
* 认证方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户名名称
String username = token.getPrincipal().toString();
//通过用户名获取用户对象
User user = userService.login(username, null);
//把user对象封装的AuthenticationInfo中返回
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),ByteSource.Util.bytes(user.getSalt()),"authenRealm");
return authenticationInfo;
}
}
6.登陆
@RequestMapping("/login.do")
public String login(String username,String password,HttpServletRequest request){
//当用户名称和密码都不为空的情况下,通过用户名和密码进行数据库查询校验
//获取当前的主体对象
Subject subject = SecurityUtils.getSubject();
//创建用户登录验证令牌
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);
boolean flag = subject.isAuthenticated();
if(flag){ //验证通过
//把用户对象信息放入到session中
User user = (User)subject.getPrincipal();
subject.getSession().setAttribute("user",user);
return "success";
}else{
return "login";
}
} catch (Exception e) {
e.printStackTrace();
return "login";
}
}
二、实现shiro框架的授权
1.基于xml配置文件的授权
在applicationContext-shiro中配置
<!-- 具有指定的权限才能访问 -->
/userManager.do = perms[user:manager]
/roleManager.do = perms[role:manager]
/toUserRole.do = perms[user:pression]
2.基于注解方式的授权
在springmvc配置文件中添加shiro注解的支持和spring aop代理的支持
<!-- 开启aop,对类代理 -->
<aop:config proxy-target-class="true"></aop:config>
<!-- 开启shiro注解支持 -->
<bean
class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"></property>
</bean>
在控制器上添加权限验证的注解
//需要具有function:manager权限,才能执行该控制器方法
@RequiresPermissions(value={"function:manager"})
@RequestMapping("/functionManager.do")
public String functionManager() {
return "success";
}
3.基于jsp页面标签的授权
jsp页面添加
<%@ taglib uri ="http://shiro.apache.org/tags" prefix="shiro"%>
常见标签:
扫描二维码关注公众号,回复:
6728345 查看本文章
标签名称 | 标签条件 |
---|---|
shiro:authenticated | 登陆之后 |
shiro:notAuthenticated | 没有登陆 |
shiro:guest | 用户在没有RemberMe时 |
shiro:user | 用户在RemberMe时 |
<shiro:hasAnyRoles name="admin,user"> | 在有admin和user角色时 |
<shiro:hasRole name="admin"> | 拥有角色admin |
<shiro:lacksRole name="admin"> | 没有角色admin |
<shiro:hasPermission name="abc"> | 拥有权限资源abc |
<shiro:lacksPermission name="abc"> | 没有abc权限资源 |
shiro:principal | 显示用户身份名称 |
<shiro:principal property="username"> | 显示用户身份中的属性值 |
<shiro:notAuthenticated>没有登录时显示该信息</shiro:notAuthenticated>
<shiro:authenticated>登录后显示该信息!</shiro:authenticated>
<shiro:authenticated>
登录后显示的内容!
</shiro:authenticated>
用户名:<shiro:principal property="userName"></shiro:principal><br>
密码:<shiro:principal property="password"></shiro:principal><br>
email:<shiro:principal property="email"></shiro:principal>
<br>
权限判断:
<shiro:hasPermission name="function:add">
<a href="/addFunction.do">添加菜单</a>
</shiro:hasPermission>
<shiro:hasPermission name="function:update">
<a href="/updateFunction.do">修改菜单</a>
</shiro:hasPermission>
<shiro:hasPermission name="function:delete">
<a href="/deleteFunction.do">删除菜单</a>
</shiro:hasPermission>
4.退出操作
在shiro.xml配置文件中配置退出过滤器,shiro自动完成系统的退出操作
<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
<property name="filterChainDefinitions">
<value>
...
/logout.do = logout
...
</value>
</property>
在前端页面直接调用logout.do即可销毁session退出系统
<script type="text/javascript">
function logoutSys(){
document.location.href="logout.do";
}
</script>
<input type="button" name="btn" value="退出" onclick="logoutSys()">
三、shiro集成缓存管理
1.缓存的流程
-
shiro中提供了对认证信息和授权信息的缓存,shiro默认是关闭认证信息缓存的。对于授权信息的缓存shiro默认是开启的,因为授权信息的数据量比较大,所以我们要对授权信息进行缓存
-
shiro每次授权都会通过realm获取权限信息,为了提高访问速度需要添加缓存。第一次从realm中读取权限数据,之后不再读取
2.具体步骤
(1)导入ehcache插件的依赖
<!-- 缓存依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
(2)applicationContext-shiro.xml中添加配置信息
<!-- 缓存的配置 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml" />
</bean>
<!-- session管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 配置session的失效时长,单位是毫秒 -->
<property name="globalSessionTimeout" value="100000"></property>
<!-- 删除失效的session -->
<property name="deleteInvalidSessions" value="true"></property>
</bean>
(3)添加shiro-ehcache.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!--diskStore:缓存数据持久化的目录 地址 -->
<diskStore path="E:\workspace\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
3.清除缓存
-
用户正常退出后,shiro框架会自动清除缓存信息
-
高版本的shiro框架,用户非正常登陆也会自动清除缓存信息
-
当用户权限修改后,用户再次登陆shiro会自动调用realm从数据库获取权限数据,如果在修改权限后向立即清除缓存可以调用realm的clearCache方法手动清除缓存
自定义realm类中定义如下方法:
/**
* 清除缓存
*/
public void clearCache(){
//获取当前主体对象
PrincipalCollection principal = SecurityUtils.getSubject().getPrincipals();
super.clearCache(principal); //清除缓存
}
修改权限数据后,调用该方法
@Service
public class UserServiceImpl implements IUserService {
@Resource
AuthenRealms authenRealms;
@Resource
IUserDao userDao;
public int updateUser(User user){
int result = userDao.updateByPrimaryKey(user);
//调用清除缓存的方法
authenRealms.clearCache();
return result;
}
}