一、Shiro简介
官网 http://shiro.apache.org/download.html
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
1.创建一个Maven项目
2.下载shirojar包,因为是Maven管理的 所以添加下依赖,就从中央仓库将jar包下载到本地仓库了
<dependencies> <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.4</version> </dependency> </dependencies>
这个我下的是1.2.4版本,最新版本1.4.0,不支持IniSecurityManagerFactory解析ini,显示构造函数过时 如下图
有个slf4j api 包,这个是一个api接口包,我们还要引入slf4j的实现包,否则会报警告
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> <scope>test</scope> </dependency>
<scope>标签要删除 否则会报如下错误
3.在src/main/resources/目录下新建个shiro配置文件File,shiro.ini
建好后会弹出个记事本,关闭,不用记事本打开,右键选中openwith选TextEditor
[users] //用户
Robin=123456 //用户名=密码
Tom=123
4.在src/main/resources/目录下加个log4j.properties日志文件
5.在src/main/java目录下建个包com.guo.shiro,包下新建个类HelloWorld.java
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; public class HelloWorld { public static void main(String[] args) { // 读取配置文件,初始化SecurityManager工厂 Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini"); // 获取securityManager实例 SecurityManager securityManager=factory.getInstance(); // 把securityManager实例绑定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到当前执行的用户 Subject currentUser=SecurityUtils.getSubject(); // 创建token令牌,用户名/密码 UsernamePasswordToken token=new UsernamePasswordToken("Robin", "123456"); try{ // 身份认证 currentUser.login(token); System.out.println("身份认证成功!"); }catch(AuthenticationException e){ e.printStackTrace(); System.out.println("身份认证失败!"); } // 退出 currentUser.logout(); } }
这个身份验证获取的用户名和密码 是配置文件shiro.ini中的,要获取和验证数据库中的用户名和密码,往下看
三、身份认证
1、Subject 认证主体
Subject 认证主体包含两个信息: Principals:身份,可以是用户名,邮件,手机号码等,用来标识一个登录主体身份; Credentials:凭证,常见有密码,数字证书等等;
2、身份认证流程
Subject认证主体调用login()方法,传给SecurityManager处理,SecurityManager里有个
Authenticator实例,有个AuthenticatoStrategy策略,要读取安全数据的话
涉及到Realm 来获取安全数据
3、Realm
Realm:意思是域,Shiro 从 Realm 中获取验证数据; Realm 有很多种类,例如常见的 jdbcrealm,jndirealm,text realm。
4.以JDBCReaml 为例
a、 新建个db_shiro 库,建个users表,添加用户名Robin,密码123456
b、在mvnrepori 查找C3P0 依赖代码 和commons-logging 阿帕奇的公共日志 依赖代码
还有mysql的驱动包 依赖代码 贴入pom
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency>
c、新建个jdbc_reaml.ini配置JDBCReaml
[main]
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://localhost:3306/db_shiro
dataSource.user=root
dataSource.password=123456
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource 是下图中的jar包
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
(相当于实例化一个ComboPooledDataSource的对象dataSource)
dataSource.driverClass=com.mysql.jdbc.Driver
(相当于对象dataSource调用ComboPooledDataSource类中的setdiverClass方法,将mysql驱动设置进去)
jdbcRealm.dataSource=$dataSource
(将dataSource=com.mchange.v2.c3p0.ComboPooledDataSource中的dataSource对象赋值给
jdbcRealm.dataSource,用$相当于将dataSource对象引用过去。jdbcRealm点后的这个dataSource是下图中的setDataSource方法参数
将jdbcRealm放入securityManager中,securityManager可以放多个属性用逗号隔开。
d、下来package com.guo.shiro.HelloWorld.java中代码
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; public class HelloWorld { public static void main(String[] args) { // 读取配置文件,初始化SecurityManager工厂 Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:jdbc_reaml.ini"); // 获取securityManager实例 SecurityManager securityManager=factory.getInstance(); // 把securityManager实例绑定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到当前执行的用户 Subject currentUser=SecurityUtils.getSubject(); // 创建token令牌,用户名/密码 UsernamePasswordToken token=new UsernamePasswordToken("Robin", "123456"); try{ // 身份认证 currentUser.login(token); System.out.println("身份认证成功!"); }catch(AuthenticationException e){ e.printStackTrace(); System.out.println("身份认证失败!"); } // 退出 currentUser.logout(); } }
5、错误
建表名为users ,不能建为t_user会报错