shiro的作用
shiro是一个安全框架。主要可以帮助我们解决程序开发中认证和授权的问题。上次做的权限系统,权限控制的粒度到模块级别了,如果只要能看到操作的菜单,就能操作菜单下所有的功能。以后这种权限设计模式,可能不太好满足什么的需求的需要?以后项目中,有坑你权限粒度控制的更细,有可能要控制到模块下的按钮级别,更有甚者,控制到数据的级别。以后为了方便各种各样的常用的权限管理需求的实现。我们有必要使用了比较好的安全框架。早期的Spring Security作为一个比较完善的安全框架比较火,但是spring security学习成本比较高。之后又出现了一个shiro的安全框架,学习成本降低了很多。而且基本的功能也比较完善。shiro也提供很多其他的功能:
shiro的架构
Subject:主题 被验证的对象,一般指的当前用户对象。但是不仅仅可以指当前用户对象,还可以是是其他东西,
线程等等。spring mvc中一个一个的用户的请求。
SecurityManager:安全认证管理器。是shiro的核心,会在安全认证管理器中所做所有的认证操作。类似于之前
spring mvc中的前端控制器(DispacherServlet)
Realm: 域的意思。负责访问安全认证数据。shiro 框架并不存储安全认证数据,安全认证数据需要用户自己存
储。shiro支持很多的Realm实现,也就 是说安全认证数据我们可以放到数据库中,也可以放到文件中等等。
可以把realm理解为以前web项目中的dao层。
shiro的认证
要做一个最简单的shiro的框架。实现的功能:用户的登录身份认证。用户如果用户名和密码都输入正确,认证成功,否则认证失败。
第一步,新建maven项目,导入shiro的jar包
现在使用的maven项目还是一个简单的java项目,暂时不使用web项目。
<!--导入shiro依赖的commons-loggin的jar包--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.0.4</version> </dependency> <!--导入shiro的jar包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency>
第二步,创建shiro的认证文件
这次我们需要把用户的认证信息放到认证文件中。在resources下面建立shiro.ini:
#声明用户的对象 [users] #=号前面是用户名 后面是密码 zhang=123456 li=654321
第三步,创建测试类
/** * 测试shiro身份认证 */ public class Test01 { 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 subject = SecurityUtils.getSubject(); //声明要比对的用户名和密码的用户对象 相当于之前前台传过来的要校验的用户登录的信息 UsernamePasswordToken token = new UsernamePasswordToken("zhansdd","123"); try { //进行用户校验 subject.login(token); System.out.println("校验成功"); }catch (UnknownAccountException e){ System.out.println("您输入的用户名不存在"); }catch (IncorrectCredentialsException e){ System.out.println("您输入的密码不正确"); }catch (AuthenticationException e){ System.out.println("校验失败"); } //退出登录 subject.logout(); } }
realm
realm是用来读取认证的数据,上一个例子的认证的数据是存储在配置文件中的,一般项目认证数据都不会存到配
置文件中,一般在数据中,所以针对这种情况 我们就需要自定义realm。
自定义realm
第一步,声明自定义realm
/** * 自定义realm1 */ public class MyRealm implements Realm { //设置本realm的名称 public String getName() { return "MyRealm1"; } //设置本realm支持什么样的数据校验 public boolean supports(AuthenticationToken authenticationToken) { return authenticationToken instanceof UsernamePasswordToken; } //获取认证信息 public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //获取用户传递过来的用户名和密码 String username = (String)authenticationToken.getPrincipal(); String password = new String((char[])(authenticationToken.getCredentials())); //根据用户名和密码查询数据库,看看能不能查询到数据 if(username.equals("zhangsan")&&password.equals("123456")){ return new SimpleAuthenticationInfo(username,password,this.getName()); }else{ //校验失败 抛出校验失败异常 throw new AuthenticationException("用户名或者密码错误"); } } }
第二步,在shiro的主配置文件中声明我们自定义的realm
创建shiro的主配置文件shiro-custom.ini:
#声明自定义的realm myRealm1=com.aaa.shiro.realm.MyRealm #设置安全管理器使用我们自定义的realm securityManager.realms=$myRealm1
第三步,测试
/** * 测试shiro身份认证 自定义realm */ public class Test02 { public static void main(String[] args) { //创建生成SecurityManager的工厂类对象 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-custom.ini"); //创建SecurityManager对象 SecurityManager securityManager = factory.getInstance(); //把SecurityManager对象设置给SecurityUtils对象 SecurityUtils.setSecurityManager(securityManager); //获取验证的主题,主题是用户对象 Subject subject = SecurityUtils.getSubject(); //声明要比对的用户名和密码的用户对象 相当于之前前台传过来的要校验的用户登录的信息 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan123","123456"); try { //进行用户校验 subject.login(token); System.out.println("校验成功"); }catch (UnknownAccountException e){ System.out.println("您输入的用户名不存在"); }catch (IncorrectCredentialsException e){ System.out.println("您输入的密码不正确"); }catch (AuthenticationException e){ System.out.println("校验失败"); } //退出登录 subject.logout(); } }
JdbcRealm
jdbcRealm的实现允许我们从一个数据源中读取认证的数据,只需要简单的配置即可。
假如要从oracle数据库中读取认证数据
第一步,在oracle中创建用户认证需要的表
JdbcRealm默认会找数据库中名称为Users的表进行查询,Users必须要有username列,password列。
第二步,引入oracle的驱动包,数据库连接池实现的包dbcp
第三步,在shiro主配置文件中配置JdbcRealm
在resources下面创建shiro-jdbcrealm.ini:
#声明数据源 dataSource=org.apache.commons.dbcp.BasicDataSource #声明数据源的一些链接的属性 dataSource.driverClassName=oracle.jdbc.driver.OracleDriver dataSource.url=jdbc:oracle:thin:@localhost:1521:orcl dataSource.username=scott dataSource.password=tiger #声明jdbcrealm jdbcrealm=org.apache.shiro.realm.jdbc.JdbcRealm #声明jdbcrealm需要用到的数据源属性 jdbcrealm.dataSource=$dataSource ##设置安全管理器使用的jdbcrealm securityManager.realms=$jdbcrealm
第四步,测试
/** * 测试shiro身份认证 自定义realm */ public class Test03 { public static void main(String[] args) { //创建生成SecurityManager的工厂类对象 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-jdbcrealm.ini"); //创建SecurityManager对象 SecurityManager securityManager = factory.getInstance(); //把SecurityManager对象设置给SecurityUtils对象 SecurityUtils.setSecurityManager(securityManager); //获取验证的主题,主题是用户对象 Subject subject = SecurityUtils.getSubject(); //声明要比对的用户名和密码的用户对象 相当于之前前台传过来的要校验的用户登录的信息 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123456"); try { //进行用户校验 subject.login(token); System.out.println("校验成功"); }catch (UnknownAccountException e){ System.out.println("您输入的用户名不存在"); }catch (IncorrectCredentialsException e){ System.out.println("您输入的密码不正确"); }catch (AuthenticationException e){ e.printStackTrace(); System.out.println("校验失败"); } //退出登录 subject.logout(); } }