springboot整合shiro,实现登录认证,登录过期,权限拦截,单点登录
1、权限控制的两种方式:粗粒度基于URL级别权限控制、细粒度基于方法级别权限控制
2、基于Apache Shiro实现登录认证和权限控制,重点讲解shiro权限控制流程、自定义Realm对象控制系统认证和授权
3、Apache Shiro实现细粒度方法级别权限控制
4、动态系统菜单显示功能
5、对认证和授权数据进行缓存优化
粗粒度 URL 级别权限控制(基于页面的访问路径)
用户发送请求,访问页面,通过配置的Filter过滤器进行拦截,判断当前用户是否具有访问页面(Url)的权限(根据shiro配置,那些页面/资源需要进行认证,那些页面/资源可以直接访问),如果有放行,如果没有提示权限不足,禁止访问
可以基于 Filter 实现(基于页面访问路径)在数据库中存放 用户、权限、访问 URL 对应关系, 当前用户访问一个 URL 地址,查询数据库判断用户当前具有权限,是否包含这个 URL,如果包含允许访问,如果不包含 权限不足 !!!
细粒度方法级别权限控制(基于HTTP方法的访问)
用户发送请求,访问方法,在方法的Service(业务逻辑层),通过注解方式,判断此用户是否具有执行方法的权限,有就放行,没有进行拦截
可以代理、自定义注解实现,访问目标对象方法,在方法上添加权限注解信息,对目标对象创建代理对象,访问真实对象先访问代理对象,在代理对象查询数据库判断是否具有注解上描述需要权限,具有权限允许访问,不具有权限,拦截访问,提示权限不足
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
Apache Shiro 组件介绍
1) Authentication 认证: 用户认证,身份识别 (你是谁?)
2) Authorization 授权:用户具有哪些权限、角色 (你能做什么?)
3) Cryptography安全数据加密
4) Session Management 会话管理
5) Web Integration web系统集成
6) Integrations 集成其他应用,spring、缓存框架
ApacheShiro运行流程和权限控制方式分析
1、核心介绍
1)Application Code用户编写代码
2)Subject就是shiro管理的用户(相当于登录的用户对象)
3)SecurityManager安全管理器,就是shiro权限控制核心对象,在编程时,只需要操作Subject方法,底层调用 SecurityManager方法,无需直接编程操作SecurityManager
4)Realm应用程序和安全数据之间连接器,应用程序进行权限控制读取安全数据(数据表、文件、网络…)通过Realm对象完 成
2、Shiro执行流程
应用程序—>Subject—>SecurityManager—>Realm—>安全数据
3、Shiro进行权限控制的四种主要方式
1)在程序中通过Subject编程方式进行权限控制
2)配置Filter实现URL级别粗粒度权限控制
3)配置代理,基于注解实现细粒度权限控制
4)在页面中使用shiro自定义标签实现,页面显示权限控制
引入maven依赖
<!--springboot整合shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- shiro 缓存框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<!-- thymeleaf支持shiro注解 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
配置shiroconfig 核心配置类
@Configuration
public class ShiroConfig {
@Bean // shiroFilter 过滤器
public ShiroFilterFactoryBean shirFilter(org.apache.shiro.mgt.SecurityManager securityManager) {
System.out.println("====ShiroConfiguration.shirFilter()====");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
shiroFilterFactoryBean.setLoginUrl("/");// 设置首页
// 登录成功后要跳转的链接
// shiroFilterFactoryBean.setSuccessUrl("/login/home");
// // 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/shiroError");
// 添加shiro内置过滤器 filterChainDefinitionMap
/*
* anon:表示可以匿名使用。 authc:表示需要认证(登录)才能使用,没有参数
* roles:参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles[
* "admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
* perms:参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms[
* "user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
* rest:根据请求的方法,相当于/admins/user/**=perms[user:method]
* ,其中method为post,get,delete等。
* port:当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,
* 其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,
* queryString是你访问的url里的?后面的参数。 authcBasic:没有参数表示httpBasic认证
* ssl:表示安全的url请求,协议为https user:当登入操作时不做检查
*/
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// // 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/", "anon"); // 可以匿名访问"/"方法
filterChainDefinitionMap.put("/kickout", "anon"); //踢出用户方法,跳转到登录页
filterChainDefinitionMap.put("/add", "authc"); // 必须认证才能访问 测试用
filterChainDefinitionMap.put("/update", "authc"); // 必须认证才能访问 测试用
filterChainDefinitionMap.put("/tologin", "anon");// 可以匿名访问"/tologin"方法
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/image/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/plugins/**", "anon");
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout"); // 退出登录方法
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
//user 验证通过或RememberMe登录的都可以 kickout 自定义过滤器(需要验证并发登录,踢出重复登录)
filterChainDefinitionMap.put("/**", "user,kickout");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//自定义拦截器 key:名称 value:filter(过滤器)
Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
//限制同一帐号同时在线的个数。
filtersMap.put("kickout", kickoutSessionControlFilter());
//设置自定义过滤器到shiro过滤器工厂
shiroFilterFactoryBean.setFilters(filtersMap);
return shiroFilterFactoryBean;
}
/**
* 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 )
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashAlgorithmName("md5");
// 散列的次数,比如散列两次 md5(md5(""));
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
}
/**
* 自定义retryLimitCredentialsMatcher的作用是为了设置一个和密码加密算法一样的算法,替代了凭证管理器HashedCredentialsMatcher
* 在注册用户时会根据设置的加密方式和次数对明文密码加密保存
* 在登录的时候会根据用户密码加密匹配DB密码,同时记录登录次数,超过限制次数限制登录时间
*/
@Bean
public RetryLimitCredentialsMatcher getRetryLimit(){
//构造方法实例化RetryLimitCredentialsM