Shiro部署
导入依赖
<!--shiro安全控制框架-->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.9</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</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-quartz</artifactId>
<version>1.2.3</version>
</dependency>
配置web.xml文件
- 让所有的请求都先经过shiro的验证
需要的配置文件
主配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
<!-- 如果在service上想使用权限注解,需要在这里也加上此段配置(spring-mvc虽然也配置了此段,但那只对controller有效) -->
<aop:config proxy-target-class="true"></aop:config>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!-- 缓存管理器 使用Ehcache实现 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
</bean>
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="sid"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="180000"/>
</bean>
<!-- 会话DAO -->
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 会话验证调度器 -->
<bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
<property name="sessionValidationInterval" value="1800000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- <bean id="sessionValidationScheduler" class="com.study.it.shiro.Quartz2SessionValidationScheduler"><!– 适应quartz的高版本 ,自己扩充的类–>
<property name="sessionValidationInterval" value="1800000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>-->
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="1800000"/>
<property name="deleteInvalidSessions" value="true"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<property name="sessionDAO" ref="sessionDAO"/>
<property name="sessionIdCookieEnabled" value="true"/>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="cacheManager" ref="cacheManager"/>
<property name="rememberMeManager" ref="rememberMeManager"/><!-- rememberMe -->
</bean>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"><!-- rememberMe -->
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="2592000"/><!-- 30天 -->
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"><!-- rememberMe -->
<!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)-->
<property name="cipherKey"
value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<!-- 基于Form表单的身份验证过滤器 -->
<bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<property name="usernameParam" value="username"/> <!-- 登录页提交的用户名和密码 -->
<property name="passwordParam" value="password"/>
<property name="loginUrl" value="/login"/>
<property name="rememberMeParam" value="rememberMe"/><!-- rememberMe -->
<property name="failureKeyAttribute" value="shiroLoginFailure"></property>
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="com.ysl.shiro.MyCredentialsMatcher"/><!-- 验证密码的子类 -->
<!-- Realm实现 -->
<bean id="userRealm" class="com.ysl.shiro.MyUserRealm" p:empService-ref="empService"><!-- 验证用户名 和加载拥有什么权限 的类-->
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<property name="cachingEnabled" value="true"/>
<property name="authenticationCachingEnabled" value="true"/>
<property name="authenticationCacheName" value="authenticationCache"/>
<property name="authorizationCachingEnabled" value="true"/>
<property name="authorizationCacheName" value="authorizationCache"/>
</bean>
<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="/login"/><!-- 指定注销后跳转到哪里 -->
</bean>
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login"/><!--登录的网址 -->
<property name="successUrl" value="/checkin"/><!-- 如果没有旧url的情况下,登录成功跳转到哪里 -->
<property name="unauthorizedUrl" value="/toDeny"/><!--无权限的时候跳转到哪里 -->
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter"/><!-- 登录的时候经过的过滤器 -->
<entry key="logout" value-ref="logoutFilter"/><!-- 注销的时候经过的过滤器 -->
</map>
</property>
<property name="filterChainDefinitions">
<value>
/css/** = anon
/js/** = anon
/imgs/** = anon
/login = authc
/logout = logout
/abc/* = user
</value>
</property>
</bean>
<!-- Shiro生命周期处理器-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
缓存配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="shirocache">
<diskStore path="java.io.tmpdir"/>
<!-- 登录记录缓存 锁定10分钟 -->
<cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="shiro-activeSessionCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
</ehcache>
Controller类
认证和授权
登录验证的代码
package com.ysl.shiro;
import com.ysl.bean.Emp;
import com.ysl.service.EmpService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class MyUserRealm extends AuthorizingRealm {
private EmpService empService;
public void setEmpService(EmpService empService) {
this.empService = empService;
}
/**
* 授权(访问控制)
* <p>
* 加载当前用户到底有哪些权限和角色
*
* 想办法加载用户权限
* 数据库/xml/第三方
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//在当前参数中提取当前的登录用户信息
Emp emp = (Emp) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//加载角色
if (emp.getRole() != null) {
//按","分割角色,获取角色的数组
String[] roleArray = emp.getRole().split(",");
for (String role : roleArray) {
System.out.println("角色为" + role);
//封装所有的角色信息
info.addRole(role);
}
}
if (emp.getPermiss() != null) {
//按","分割权限,获取权限的数组
String[] pArray = emp.getPermiss().split(",");
for (String p : pArray) {
System.out.println("权限为" + p);
//封装所有的权限信息
info.addStringPermission(p);
}
}
return info;
}
/**
* 认证(登录)
* <p>
* 查询数据库
* 比对用户名
* 读取用户信息
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户名
String username = token.getPrincipal().toString();
//根据用户名查询用户是否存在
//只验证用户名
Emp emp = empService.findByEmpName(username);
if (emp == null) {
throw new UnknownAccountException("无此账号用户");
}
System.out.println(emp);
//制作凭证用于下一步的密码验证
// 参数
// 1-是主要凭证,为了有更多的数据可用,我们压入user对象,要标记为可序列化(排除不必要的字段);
// 2-数据库记录的密码是多少;
// 3-本类的名称
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(emp, emp.getPwd(), emp.getName());
return info;
}
}
密码匹配器
package com.ysl.shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
/**
* 密码匹配器
*
* 需要通过配置文件注册到框架中
*
* @program: Day0724_Shiro
* @description
* @author: YS_LAR
* @create: 2021-07-24 15:33
**/
public class MyCredentialsMatcher implements CredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
//界面录入的密码
String input = new String((char[]) token.getCredentials());
//从数据库中获得的密码
String stand = info.getCredentials().toString();
//匹配密码
//返回true或false
return stand.equalsIgnoreCase(input);
}
}
Service层
Realm实现配置
Service实现
Dao层
Dao层xml文件编写
配置
Form表单登录数据获取配置
登录
在配置文件配置登录路径
配置mvc.xml
配置注销后跳转
访问控制
使用注解判断权限
管理员和经理的权限不同
两种角色和权限放在同一url下,需要进一步判断权限
分解成两个方法
JSP页面
导入shiro标识
取值
JSP也可以进行Shiro权限判断
异常处理
考虑ajax情况下的异常
发生异常跳转到登录页
- 错误页提供登录手段
- 在shiro主配置文件中增加配置