Shiro的配置
导入Shiro依赖库
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro‐core</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro‐web</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro‐spring</artifactId>
<version>1.4.1</version>
</dependency>
本博文配置以1.4.1版本为参考,其他版本如有出入请以官方配置为主
官方配置地址在此博文底部
SpringMVC整合Shiro
- 拦截所有请求
<?xml version="1.0" encoding="UTF‐8"?>
<web‐app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web‐app_3_1.xsd"
version="3.1">
<context‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>classpath:spring‐*.xml</param‐value>
</context‐param>
<listener>
<listener‐class>org.springframework.web.context.ContextLoaderListener</listener‐class>
</listener>
<servlet>
<servlet‐name>springMVC</servlet‐name>
<servlet‐class>org.springframework.web.servlet.DispatcherServlet</servlet‐
class>
<init‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>classpath:spring‐context*.xml</param‐value>
</init‐param>
</servlet>
<servlet‐mapping>
<servlet‐name>springMVC</servlet‐name>
<url‐pattern>*.do</url‐pattern>
</servlet‐mapping>
<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>
</web‐app>
创建spring-context-shiro.xml
配置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="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<!‐‐配置登录页面地址,非必须,默认寻找web项目根路径下的/login.jsp‐‐>
<property name="loginUrl" value="/login.jsp"></property>
<!‐‐配置登录成功之后跳转的页面路径此配置一般不使用一般在LoginController中处理逻辑‐‐>
<property name="successUrl" value="/index.jsp"></property>
<property name="unauthorizedUrl" value="/"></property>
<property name="filterChainDefinitions">
<value>/**=anon</value>
</property>
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
<!‐‐证书匹配器‐‐>
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.Md5CredentialsMatcher"></bean>
<!‐‐使用自带的Realm‐‐>
<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
<property name="permissionsLookupEnabled" value="true"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<!‐‐缓存管理‐‐>
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean>
<!‐‐shiro安全管理器‐‐>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="jdbcRealm"></property>
<property name="cacheManager" ref="cacheManager"></property>
</bean>
</beans>
如果用注解则需要配置权限验证使用注解
<!‐‐配置权限验证使用注解‐‐>
<aop:config proxy‐target‐class="true"></aop:config>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"></property>
</bean>
SpringBoot应用整合Shiro配置
- SpringBoot默认没有提供对Shiro的自动配置
java配置方式
@Configuration
public class ShiroConfig {
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
//自定义Realm
@Bean
public MyRealm getMyRealm(){
MyRealm myRealm = new MyRealm();
return myRealm;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//securityManager要完成校验,需要realm
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器就是shiro就行权限校验的核心,进行认证和授权是需要SecurityManager的
filter.setSecurityManager(securityManager);
//设置登录网址
filter.setLoginUrl("/user/login");
//设置shiro的拦截规则
// anon 匿名用户可访问
// authc 认证用户可访问
// user 使用RemeberMe的用户可访问
// perms 对应权限可访问
// role 对应的角色可访问
Map<String,String> filterMap = new HashMap<>();
filterMap.put("/","anon");
filterMap.put("/login.html","anon");
filterMap.put("/regist.html","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/regist","anon");
filterMap.put("/static/**","anon");
filterMap.put("/**","authc");
filter.setFilterChainDefinitionMap(filterMap);
filter.setLoginUrl("/login.html");
//设置未授权访问的页面路径
filter.setUnauthorizedUrl("/login.html");
return filter;
}
}
- 自定义Realm
/**
* 1.创建一个类继承AuthorizingRealm类(实现了Realm接口的类)
* 2.重写doGetAuthorizationInfo和doGetAuthenticationInfo方法
* 3.重写getName方法返回当前realm的一个自定义名称
*/
public class MyRealm extends AuthorizingRealm {
@Resource
private UserDAO userDAO;
@Resource
private RoleDAO roleDAO;
@Resource
private PermissionDAO permissionDAO;
public String getName() {
return "myRealm";
}
/**
* 获取授权数据(将当前用户的角色及权限信息查询出来)
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户的用户名
String username = (String) principalCollection.iterator().next();
//根据用户名查询当前用户的角色列表
Set<String> roleNames = roleDAO.queryRoleNamesByUsername(username);
//根据用户名查询当前用户的权限列表
Set<String> ps = permissionDAO.queryPermissionsByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roleNames);
info.setStringPermissions(ps);
return info;
}
/**
* 获取认证的安全数据(从数据库查询的用户的正确数据)
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//参数authenticationToken就是传递的 subject.login(token)
// 从token中获取用户名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据用户名,从数据库查询当前用户的安全数据
User user = userDAO.queryUserByUsername(username);
AuthenticationInfo info = new SimpleAuthenticationInfo(
username, //当前用户用户名
user.getUserPwd(), //从数据库查询出来的安全密码
getName());
return info;
}
}
Shiro使用加密认证
@Configuration
public class ShiroConfig {
//...
@Bean
public HashedCredentialsMatcher getHashedCredentialsMatcher(){
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//matcher就是用来指定加密规则(可自定义加密规则)
matcher.setHashAlgorithmName("md5");
//hash次数
matcher.setHashIterations(1); //此处的循环次数要与用户注册是密码加密次数一致
return matcher;
}
//自定义Realm
@Bean
public MyRealm getMyRealm( HashedCredentialsMatcher matcher ){
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(matcher);
return myRealm;
}
//...
}
缓存使用
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
- 配置缓存策略
在resources目录下创建一个xml文件(ehcache.xml)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
<diskStore path="C:\TEMP" />
<cache name="users" timeToLiveSeconds="300" maxEntriesLocalHeap="1000"/>
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<!--缓存淘汰策略:当缓存空间比较紧张时,我们要存储新的数据进来,就必然要删除一些老的数据
LRU 最近最少使用
FIFO 先进先出
LFU 最少使用
-->
</ehcache>
加入缓存管理(java配置)
@Bean
public EhCacheManager getEhCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return ehCacheManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
return securityManager;
}
session管理
- 配置自定义SessionManager:ShiroConfig.java
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
System.out.println("----------"+sessionManager.getGlobalSessionTimeout()); // 1800000
//配置sessionManager
sessionManager.setGlobalSessionTimeout(5*60*1000);
return sessionManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
return securityManager;
}
记住我
在过滤器中设置“记住我”可访问的url
// anon 表示未认证可访问的url
// user 表示记住我可访问的url(已认证也可以访问)
//authc 表示已认证可访问的url
//perms 表示必须具备指定的权限才可访问
//logout 表示指定退出的url
filterMap.put("/","anon");
filterMap.put("/index.html","user");
filterMap.put("/login.html","anon");
filterMap.put("/regist.html","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/regist","anon");
filterMap.put("/layui/**","anon");
filterMap.put("/**","authc");
filterMap.put("/c_add.html","perms[sys:c:save]");
filterMap.put("/exit","logout");
在ShiroConfig.java中配置基于cookie的rememberMe管理器
@Bean
public CookieRememberMeManager cookieRememberMeManager(){
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
//cookie必须设置name
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setMaxAge(30*24*60*60);
rememberMeManager.setCookie(cookie);
return rememberMeManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
//设置remember管理器
securityManager.setRememberMeManager(cookieRememberMeManager());
return securityManager;
}
登录认证时设置token“记住我”
- 登录页面
<form action="/user/login" method="post">
<p>帐号:<input type="text" name="userName"/></p>
<p>密码:<input type="text" name="userPwd"/></p>
<p>记住我:<input type="checkbox" name="rememberMe"/></p>
<p><input type="submit" value="登录"/></p>
</form>
控制器
@Controller
@RequestMapping("user")
public class UserController {
@Resource
private UserServiceImpl userService;
@RequestMapping("login")
public String login(String userName,String userPwd,boolean rememberMe){
try {
userService.checkLogin(userName,userPwd,rememberMe);
System.out.println("------登录成功!");
return "index";
} catch (Exception e) {
System.out.println("------登录失败!");
return "login";
}
}
}
service
@Service
public class UserServiceImpl {
public void checkLogin(String userName, String userPwd,boolean rememberMe) throws Exception {
//Shiro进行认证 ——入口
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
token.setRememberMe(rememberMe);
subject.login(token);
}
}
参考资料
Shiro官方配置: http://shiro.apache.org/spring.html.