Shiro权限管理框架(一):Shiro的基本使用
核心概念
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
上面这段话来自百度百科,是不是非常官方,好像说的很明白但是又好像什么都没说的样子,到底是个啥呀。想要快速理解并使用Shiro先要从最重要的三大概念入手。
- Subject:大白话来讲就是用户(当然并不一定是用户,也可以指和当前应用交互的任何对象),我们在进行授权鉴权的所有操作都是围绕Subject(用户)展开的,在当前应用的任何地方都可以通过
SecurityUtils
的静态方法getSubject()
轻松的拿到当前认证(登录)的用户。 - SecurityManager:安全管理器,Shiro中最核心的组件,它管理着当前应用中所有的安全操作,包括Subject(用户),我们围绕Subject展开的所有操作都需要与SecurityManager进行交互。可以理解为SpringMVC中的前端控制器。
- Realms:字面意思为领域,Shiro在进行权限操作时,需要从Realms中获取安全数据,也就是用户以及用户的角色和权限。配置Shiro,我们至少需要配置一个Realms,用于用户的认证和授权。通常我们的角色及权限信息都是存放在数据库中,所以Realms也可以算是一个权限相关的Dao层,SecurityManager在进行鉴权时会从Realms中获取权限信息。
这三个基本的概念简答理解后就可以开始配置和使用Shiro了,其实Shiro最基本的使用非常简单,加入依赖后只需要配置两个Bean,再继承一个抽象类实现两个方法即可。
首发地址:https://www.guitu18.com/post/2019/07/26/43.html
基本使用
引入一个依赖
新建一个基于Springboot的Web项目,引入Shiro依赖。
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
配置两个Bean
新建一个Shiro配置类,配置Shiro最为核心的安全管理器SecurityManager。
@Bean
public SecurityManager securityManager(UserAuthorizingRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
securityManager.setRememberMeManager(null);
return securityManager;
}
再配置Shiro的过滤器工厂类,将上一步配置的安全管理器注入,并配置相应的过滤规则。
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 登录页面,无权限时跳转的路径
shiroFilterFactoryBean.setLoginUrl("/login");
// 配置拦截规则
Map<String, String> filterMap = new LinkedHashMap<>();
// 首页配置放行
filterMap.put("/", "anon");
// 登录页面和登录请求路径需要放行
filterMap.put("/login", "anon");
filterMap.put("/do_login", "anon");
// 其他未配置的所有路径都需要通过验证,否则跳转到登录页
filterMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
上面使用LinkedHashMap是为了保持顺序,Filter的配置顺序不能随便打乱,过滤器是按照我们配置的顺序来执行的。范围大的过滤器要放在后面,/**
这条如果放在前面,那么一来就匹配上了,就不会继续再往后走了。这里的对上面用到的两个过滤器做一下简单说明,篇幅控制其他过滤器请参阅相关文档:
* authc:配置的url都必须认证通过才可以访问,它是Shiro内置的一个过滤器
* 对应的实现类 @see org.apache.shiro.web.filter.authc.FormAuthenticationFilter
* anon:也是Shiro内置的,它对应的过滤器里面是空的,什么都没做,可以理解为不拦截
* 对应的实现类 @see org.apache.shiro.web.filter.authc.AnonymousFilter
实现两个方法
在上一步的安全管理器配置中,我们通过形参注入了一个UserAuthorizingRealm对象,这个就是认证和授权相关的流程,需要我们自己实现。继承AuthorizingRealm之后,我们需要实现两个抽象方法,一个是认证,一个是授权,这两个方法长得很像,别弄混淆了。
doGetAuthenticationInfo():认证。相当于登录,只有通过登录了,才能进行后面授权的操作。一些只需要登录权限的操作,在登录成功后就可以访问了,比如上一步中配置的authc
过滤器就是只需要登录权限的。
doGetAuthorizationInfo():授权。认证过后,仅仅拥有登录权限,更多细粒度的权限控制,比如菜单权限,按钮权限,甚至方法调用权限等,都可以通过授权轻松实现。在这个方法里,我们可以拿到当前登录的用户,再根据实际业务赋予用户部分或全部权限,当然这里也可以赋予用户某些角色,后面也可以根据角色鉴权。下方的演示代码仅添加了权限,赋予角色可以调用addRoles()
或者setRoles()
方法,传入角色集合。
public class UserAuthorizingRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
/**
* 授权验证,获取授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
List<String> perms;
// 系统管理员拥有最高权限
if (User.SUPER_ADMIN == user.getId()) {
perms = loginService.getAllPerms();
} else {
perms = loginService.getUserPerms(user.getId());
}
// 权限Set集合
Set<String> permsSet = new HashSet<>();
for (String perm : perms) {
permsSet.addAll(Arrays.asList(perm.trim().split(",")));
}
// 返回权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
}
/**
* 登录验证,获取身份信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
// 获取用户
User user = loginService.getUserByUsername(token.getUsername());
if (user == null) {
throw new UnknownAccountException("账号或密码不正确");
}
// 判断用户是否被锁定
if (user.getStatus() == null || user.getStatus() == 1) {
throw new LockedAccountException("账号已被锁定,请联系管理员");
}
// 验证密码
if (!user.getPassword().equals(new String(token.getPassword()))) {
throw new UnknownAccountException("账号或密码不正确");
}
user.setSessionId(SecurityUtils.getSubject().getSession().getId().toString());
// 设置最后登录时间
user.setLastLoginTime(new Date());
// 此处可以持久化用户的登录信息,这里仅做演示没有连接数据库
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
这样配置完成以后,就可以基于URL做粗粒度的权限控制了,我们可以通过不同的过滤器为URL配置不同的权限。
Shiro提供了很多内置的过滤器,我们最常用的就是第一个和第二个。如果对其效果不满意,我们还可以自定义过滤器实现权限控制。
文档地址:http://shiro.apache.org/web.html#default-filters
细粒度权限控制
如果需要更细致的权限控制,请继续往下添加配置,可以做到方法级别的权限控制。其实在SpringMVC中URL也能做到方法级别控制,但是使用URL来控制方法级别的权限配置起来简直反人类,通常URL权限控制通常都是泛解析,做通用的权限配置,比如后台管理的/admin/**
这种需要登录权限的。在实际开发中注解式的权限控制用的最多。
AdvisorAutoProxyCreator
注解式的权限控制需要配置两个Bean,第一个是AdvisorAutoProxyCreator,代理生成器,需要借助SpringAOP来扫描@RequiresRoles和@RequiresPermissions等注解,生成代理类实现功能增强,从而实现权限控制。需要配合AuthorizationAttributeSourceAdvisor一起使用,否则权限注解无效。
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
return autoProxyCreator;
}
AuthorizationAttributeSourceAdvisor
上面配置的DefaultAdvisorAutoProxyCreator相当于一个切面,下面这个类就相当于切点了,两个一起才能实现注解权限控制。
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
配置完上面两个Bean之后我们就可以使用注解来控制权限了,Shiro中的权限注解有很多,我们最常用的其实就两个,@RequiresRoles和@RequiresPermissions,前者是角色验证,后者是权限验证。他们都可以传入两个参数,value是必须的,可以传入一个字符数组,表示一个或多个角色(权限),另一个参数logical有两个值可选,AND和OR,默认为AND,表示这组角色(权限)是必须都有还是仅需要一个就能访问。
举个栗子:
@RequestMapping("getLoginUserInfo")
@RequiresPermissions(value = {"user:list", "user:info"}, logical = Logical.OR)
public JsonResult getLoginUserInfo() {
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
return JsonResult.ok(user);
}
以上代码表示getLoginUserInfo()
方法需要当前登录用户拥有user:list
或者user:list
权限才能访问。
最后放上项目代码,其实代码是很早之前的,今天才做的笔记而已。
Gitee:https://gitee.com/guitu18/ShiroDemo
GitHub:https://github.com/guitu18/ShiroDemo
本篇结束,Shiro的使用还是非常简单的。下一篇,准备记录一下基于Springboot和Shiro使用Redis实现集群环境的Session共享,以实现单点登录。
Shiro权限管理框架(一):Shiro的基本使用的更多相关文章
- Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享
首发地址:https://www.guitu18.com/post/2019/07/28/44.html 本篇是Shiro系列第二篇,使用Shiro基于Redis实现分布式环境下的Session共享. ...
- Shiro权限管理框架(三):Shiro中权限过滤器的初始化流程和实现原理
本篇是Shiro系列第三篇,Shiro中的过滤器初始化流程和实现原理.Shiro基于URL的权限控制是通过Filter实现的,本篇从我们注入的ShiroFilterFactoryBean开始入手,翻看 ...
- Shiro权限管理框架(四):深入分析Shiro中的Session管理
其实关于Shiro的一些学习笔记很早就该写了,因为懒癌和拖延症晚期一直没有落实,直到今天公司的一个项目碰到了在集群环境的单点登录频繁掉线的问题,为了解决这个问题,Shiro相关的文档和教程没少翻.最后 ...
- Shiro权限管理框架(五):自定义Filter实现及其问题排查记录
明确需求 在使用Shiro的时候,鉴权失败一般都是返回一个错误页或者登录页给前端,特别是后台系统,这种模式用的特别多.但是现在的项目越来越多的趋向于使用前后端分离的方式开发,这时候就需要响应Json数 ...
- Shiro权限管理框架
一.Shiro介绍 Apache Shiro 是Java 的一个安全框架.Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE 环境,也可以用在JavaEE 环境.Shiro 可以 ...
- Shiro权限管理框架详解
1 权限管理1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被 ...
- shiro权限管理框架与springmvc整合
shiro是apache下的一个项目,和spring security类似,用于用户权限的管理‘ 但从易用性和学习成本上考虑,shiro更具优势,同时shiro支持和很多接口集成 用户及权限管理是众多 ...
- Shiro 权限管理框架
一.什么是Shiro Apache Shiro是一个强大易用的java安全框架,提供认证.授权.加密和会话管理等功能 · 认证:用户身份识别,俗称“登录”: · 授权:访问控制 · 密码加密:保护或隐 ...
- Springboot集成权限管理框架apache shiro
一.名词解释 网上一大堆 二.pom依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifact ...
随机推荐
- 浅谈Java中的命名规范
现代软件架构的复杂性需要协同开发完成,如何高效地协同呢? 答案是:制定一整套统一的规范. 无规矩不成方圆,无规范难以协同,比如,制订交通法规表面上是要限制行车权,实际上是保障公众的人身安全,试想如果没 ...
- Java虚拟机详解(一)------简介
本系列博客我们将以当前默认的主流虚拟机HotSpot 为例,详细介绍 Java虚拟机.以 JDK1.7 为主,同时介绍与 JDK1.8 的不同之处,通过Oracle官网以及各种文献进行整理,并加以验证 ...
- Python 爬虫从入门到进阶之路(九)
之前的文章我们介绍了一下 Python 中的正则表达式和与爬虫正则相关的 re 模块,本章我们就利用正则表达式和 re 模块来做一个案例,爬取<糗事百科>的糗事并存储到本地. 我们要爬取的 ...
- Spring事物管理简介 (转)
一.事物1.什么是事物 事物指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败 2.事物的特性 原子性:事物是一个不可分割的工作单位,事物中的操作要么都发生,要么都不发生 一致性:事物前后数据 ...
- HTTP&HTTPS
主要参考文档:<图解HTTP> HTTP简介 什么是HTTP? HTTP:(HyperText Transfer Protocol),超文本传输协议,是一个基于请求和响应,无状态的,应用层 ...
- Python开发【第九篇】: 并发编程
内容概要 操作系统介绍 进程 线程 协程 二. 进程 python并发编程之多进程理论部分 在python程序中的进程操作 运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起 ...
- K8s集群部署(一)------ETCD集群部署
环境说明 三台主机: k8s-master 10.0.3.225 k8s-node1 10.0.3.226 k8s-node2 10.0.3.227 配置主机名解析 [root@k8s- ...
- CSS3之响应式布局及其应用
使用 Media 属性前需添加兼容移动设备优先代码 <meta name=”viewport”content=”width=device-width,initial-scale=1.0,maxi ...
- kafka源码分析(一)server启动分析
1 启动入口Kafka.scala Kafka的启动入口是Kafka.scala的main()函数: def main(args: Array[String]): Unit = { try { //通 ...
- Html5学习导航
给大家推荐一下学习研究HTML5必备的一些个网站,更加有利于大家对HTML5的学些和研究.如果各位童鞋还有更多的,欢迎投递资源给我们,也可以支持我们,让我们利用大家的力量收集更多的HTML5学习资料, ...