本系列内容大多总结自官网和张开涛的《跟我学Shiro》
一、shiro简介
1.1、shiro有什么用?
shiro是一个功能强大使用简单的java安全框架,主要提供了五大功能:
1、认证:用户身份认证,也就是登陆;
2、授权-访问控制:通过一些配置,用户登录后会自动被赋予相应的身份和操作权限,实现访问控制;
3、密码加密-保护或隐藏数据防止被偷窥;
4、会话管理
5、缓存
shiro还支持一些辅助特性,如Web应用安全、单元测试和多线程,它们的存在强化了上面提到的五个要素。
1.2、shiro与Spring Security那个好?
Spring Security:除了不能脱离Spring,shiro具有的功能它都有,权限细粒度高,还提供许多其它的功能(笔者没用过,具体哪些功能不清楚),而shiro则需要手动去实现。但是与shiro相比,操作太复杂,概念多,难理解,学习成本高。
shiro:使用简单直接,上手快,控制粒度可糙可细,扩展性强,自由度高,学习成本低。但功能比Spring Security要少些。
个人观点:我认为在满足基本功能需求的情况下具有下面这两个要素就可以称之为好框架了:
一是简单易用,学习成本低。二是扩展性强,自由度高。
shiro无疑比Spring Security更具有优势,虽然Spring Security功能更强,但shiro具有的功能已经能满足大部分开发需求了;
二、shiro的外部结构
什么是外部结构?这里说的外部结构就是指开发过程中会用到shiro API。
Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;
shiro的所有功能,如认证,授权等,直接操作Subject实现;
所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;
可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;
可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;
也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;
可以把Realm看成DataSource,即安全数据源。
也就是说,shiro不自动提供给用户权限,需要开发人员在代码中通过Realm注入。
简单点来说,最简单的一个Shiro应用:
1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
三、一个简单的shiro登录实例
2.1、引入包
这里我用的maven构建项目。
因为shiro依赖slf4j,maven仅帮我们下载slf4j的API,所以我们最好导入slf4j的实现,否则会有警告。
POM文件
Maven下载的包
2.2、创建ini配置文件
在ini配置文件中,输入账号和密码。这里为了方便演示所以使用ini配置文件,在实际项目中这些数据都要放在数据库中。
2.3、创建测试类
public static void main(String[] args) { // 1、读取配置文件,初始化SecurityManager工厂 Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini"); ///2、获取securityManager实例 SecurityManager securityManager=factory.getInstance(); ///3、把securityManager实例绑定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); ///4、得到当前执行的用户 Subject currentUser=SecurityUtils.getSubject(); ///5、创建token令牌,用户名/密码 UsernamePasswordToken token=new UsernamePasswordToken("java1234", "12345"); try{ ///6、身份认证 currentUser.login(token); System.out.println("身份认证成功!"); }catch(AuthenticationException e){ e.printStackTrace(); System.out.println("身份认证失败!"); } // 退出 currentUser.logout(); }
1、通过 new IniSecurityManagerFactory 并指定一个 ini 配置文件来创建一个 SecurityManager 工厂,这种方法只是用于测试,实际开发不使用。
2、获取 SecurityManager 并绑定到 SecurityUtils,这是一个全局设置,设置一次即可,实际开发中在配置中完成;
3、通过 SecurityUtils 得到 Subject,其会自动绑定到当前线程;如果在 web 环境在请求结束时需要解除绑定;然后获取身份验证的 Token,如用户名 / 密码;
4、调用 subject.login 方法进行登录,其会自动委托给 SecurityManager.login 方法进行登录;
5、如果身份验证失败请捕获 AuthenticationException 或其子类,常见的如:
DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、
UnknownAccountException(错误的帐号)、ExcessiveAttemptsException(登录失败次数过多)、
IncorrectCredentialsException (错误的凭证)、ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;