什么是Shiro

shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权

spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。

shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。

Shiro架构:

  • subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
  • securityManager:安全管理器,主体进行认证和授权都 是通过securityManager进行。
  • authenticator:认证器,主体进行认证最终通过authenticator进行的。
  • authorizer:授权器,主体进行授权最终通过authorizer进行的。
  • sessionManager:web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。
  • SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。
  • cache Manager:缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理。
  • realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。

cryptography:密码管理,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。

  • 比如md5散列算法。

为什么使用Shiro

我们在使用URL拦截的时候,要将所有的URL都配置起来,繁琐、不易维护

而我们的Shiro实现系统的权限管理,有效提高开发效率,从而降低开发成本。

Shiro认证

导入jar包

我们使用的是Maven的坐标就行了


<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.2.3</version>
</dependency>

当然了,我们也可以把Shiro相关的jar包全部导入进去


<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>

Shiro认证流程

通过配置文件创建工厂


// 用户登陆和退出
@Test
public void testLoginAndLogout() { // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-first.ini"); // 创建SecurityManager
SecurityManager securityManager = factory.getInstance(); // 将securityManager设置当前的运行环境中
SecurityUtils.setSecurityManager(securityManager); // 从SecurityUtils里边创建一个subject
Subject subject = SecurityUtils.getSubject(); // 在认证提交前准备token(令牌)
// 这里的账号和密码 将来是由用户输入进去
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
"111111");
try {
// 执行认证提交
subject.login(token);
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 是否认证通过
boolean isAuthenticated = subject.isAuthenticated(); System.out.println("是否认证通过:" + isAuthenticated); // 退出操作
subject.logout(); // 是否认证通过
isAuthenticated = subject.isAuthenticated(); System.out.println("是否认证通过:" + isAuthenticated); }

小结

ModularRealmAuthenticator作用进行认证,需要调用realm查询用户信息(在数据库中存在用户信息)

ModularRealmAuthenticator进行密码对比(认证过程)。

realm:需要根据token中的身份信息去查询数据库(入门程序使用ini配置文件),如果查到用户返回认证信息,如果查询不到返回null

自定义realm

从第一个认证程序我们可以看见,我们所说的流程,是认证器去找realm去查询我们相对应的数据。而默认的realm是直接去与配置文件来比对的,一般地,我们在开发中都是让realm去数据库中比对。

因此,我们需要自定义realm


public class CustomRealm extends AuthorizingRealm { // 设置realm的名称
@Override
public void setName(String name) {
super.setName("customRealm");
} // 用于认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException { // token是用户输入的
// 第一步从token中取出身份信息
String userCode = (String) token.getPrincipal(); // 第二步:根据用户输入的userCode从数据库查询
// .... // 如果查询不到返回null
//数据库中用户账号是zhangsansan
/*if(!userCode.equals("zhangsansan")){//
return null;
}*/ // 模拟从数据库查询到密码
String password = "111112"; // 如果查询到返回认证信息AuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userCode, password, this.getName()); return simpleAuthenticationInfo;
} // 用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
} }

配置realm

需要在shiro-realm.ini配置realm注入到securityManager中。

测试自定义realm

同上边的入门程序,需要更改ini配置文件路径:


同上边的入门程序,需要更改ini配置文件路径:
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-realm.ini");

散列算法

我们如果知道md5,我们就会知道md5是不可逆的,但是如果设置了一些安全性比较低的密码:111111…即时是不可逆的,但还是可以通过暴力算法来得到md5对应的明文…

建议对md5进行散列时加salt(盐),进行加密相当 于对原始密码+盐进行散列。\

正常使用时散列方法:

  • 在程序中对原始密码+盐进行散列,将散列值存储到数据库中,并且还要将盐也要存储在数据库中。

测试:


public class MD5Test { public static void main(String[] args) { //原始 密码
String source = "111111";
//盐
String salt = "qwerty";
//散列次数
int hashIterations = 2;
//上边散列1次:f3694f162729b7d0254c6e40260bf15c
//上边散列2次:36f2dfa24d0a9fa97276abbe13e596fc //构造方法中:
//第一个参数:明文,原始密码
//第二个参数:盐,通过使用随机数
//第三个参数:散列的次数,比如散列两次,相当 于md5(md5(''))
Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations); String password_md5 = md5Hash.toString();
System.out.println(password_md5);
//第一个参数:散列算法
SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
System.out.println(simpleHash.toString());
} }

自定义realm支持md5

自定义realm


public class CustomRealmMd5 extends AuthorizingRealm { // 设置realm的名称
@Override
public void setName(String name) {
super.setName("customRealmMd5");
} // 用于认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException { // token是用户输入的
// 第一步从token中取出身份信息
String userCode = (String) token.getPrincipal(); // 第二步:根据用户输入的userCode从数据库查询
// .... // 如果查询不到返回null
// 数据库中用户账号是zhangsansan
/*
* if(!userCode.equals("zhangsansan")){// return null; }
*/ // 模拟从数据库查询到密码,散列值
String password = "f3694f162729b7d0254c6e40260bf15c";
// 从数据库获取salt
String salt = "qwerty";
//上边散列值和盐对应的明文:111111 // 如果查询到返回认证信息AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userCode, password, ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo;
} // 用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
} }

配置文件:

测试:


// 自定义realm实现散列值匹配
@Test
public void testCustomRealmMd5() { // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-realm-md5.ini"); // 创建SecurityManager
SecurityManager securityManager = factory.getInstance(); // 将securityManager设置当前的运行环境中
SecurityUtils.setSecurityManager(securityManager); // 从SecurityUtils里边创建一个subject
Subject subject = SecurityUtils.getSubject(); // 在认证提交前准备token(令牌)
// 这里的账号和密码 将来是由用户输入进去
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
"222222"); try {
// 执行认证提交
subject.login(token);
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 是否认证通过
boolean isAuthenticated = subject.isAuthenticated(); System.out.println("是否认证通过:" + isAuthenticated); }

Shiro第二篇【介绍Shiro、认证流程、自定义realm、自定义realm支持md5】的更多相关文章

  1. Shiro第一篇【Shiro的基础知识、回顾URL拦截】

    Shiro基础知识 在学习Shiro这个框架之前,首先我们要先了解Shiro需要的基础知识:权限管理 什么是权限管理? 只要有用户参与的系统一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安 ...

  2. IOS百度地图之--->第二篇《大头针__简单使用及自定义》

    呵呵!大家不要只看帖不回帖么,要不然我都没有积极性了. 第一步:创建一个用来呈现mapview的viewcontroller,不废话直接贴代码        BasicMapViewControlle ...

  3. 第二篇:git创建流程

    1.创建组织 2.创建 3.点击项目 创建完: 4.选择管理——>选择公钥——>添加个人公钥: 5.怎样生成公钥 5.1.如何生成ssh公钥 你可以按如下命令来生成 sshkey: ssh ...

  4. [转]Spring Security Oauth2 认证流程

    1.本文介绍的认证流程范围 本文主要对从用户发起获取token的请求(/oauth/token),到请求结束返回token中间经过的几个关键点进行说明. 2.认证会用到的相关请求 注:所有请求均为po ...

  5. Kerberos认证流程详解

    Kerberos是诞生于上个世纪90年代的计算机认证协议,被广泛应用于各大操作系统和Hadoop生态系统中.了解Kerberos认证的流程将有助于解决Hadoop集群中的安全配置过程中的问题.为此,本 ...

  6. 菜鸟手把手学Shiro之shiro认证流程

    一.使用的spring boot +mybatis-plus+shiro+maven来搭建项目框架 <!--shiro--> <dependency> <groupId& ...

  7. Shiro learning - 认证流程(3)

    Shiro认证流程 在学习认证流程之前,你应该先了解Shiro的基本使用流程 认证 身份认证: 证明用户是谁.用户需要提供相关的凭证principals(身份标识)和Credentials (凭证,证 ...

  8. Shiro(一):Shiro介绍及主要流程

    什么是Shiro Apache Shiro是一个强大且灵活的开源安全框架,易于使用且好理解,撇开了搭建安全框架时的复杂性. Shiro可以帮助我们做以下几件事: 认证使用者的身份 提供用户的访问控制, ...

  9. Shiro权限管理框架(三):Shiro中权限过滤器的初始化流程和实现原理

    本篇是Shiro系列第三篇,Shiro中的过滤器初始化流程和实现原理.Shiro基于URL的权限控制是通过Filter实现的,本篇从我们注入的ShiroFilterFactoryBean开始入手,翻看 ...

随机推荐

  1. Selenium1 Selenium2 WebDriver

    1.Selenium 1 原理 (1).测试用例(Testcase)通过Client Lib的接口向Selenium Server发送Http请求,要求和Selenium Server建立连接. 为什 ...

  2. Oracle锁表查询与解锁

    锁表查询和解锁 --查询SELECT object_name, machine, s.sid, s.serial# FROM gv$locked_object l, dba_objects o, gv ...

  3. 在Python3.5中使用 The del.icio.us API

    问题:参考<集体智慧编程>一书的第二章中访问del.icio.us网站的数据需要使用到事先编好的Python API.但是书上提供的API并不适用与Python3.5的版本. 解决方法:在 ...

  4. 第一天的Python之路 笔记

     打了***号的都是老师要求明天早上默写的  编程语言的作用(程序员使用的编程语言达到命令电脑工作的目的)及与操作系统和硬件的关系(编程 语言用来开发软件,软件基于操作系统之上,操作系统又基于硬件之上 ...

  5. jeecg 3.7.1 新版功能,集群定时任务动态发布模块 使用规则

    jeecg 3.7.1  集群定时任务动态发布模块 使用规则   新版特性:    支持集群定时任务,支持分布式. 菜单路径: 系统监控-->定时任务 字段说明: 任务ID.任务说明:自定义即可 ...

  6. jQuery事件对象

    1.event.currentTarget 事件的监听者2.event.target 事件的目标3.event.delegateTarget 绑定了当前正在调用jQuery事件处理器的(当前事件的委托 ...

  7. struts2-Action处理请求参数

    struts2 和 MVC 定义关系 StrutsPrepareAndExecuteFilter : 控制器 JSP : 视图 Action : 可以作为模型,也可以是控制器 struts2 Acti ...

  8. Mybatis --- 创建方法、全局配置

    总体介绍:MyBatis实际上是Ibatis3.0版本以后的持久化层框架[也就是和数据库打交道的框架]!     和数据库打交道的技术有:      原生的JDBC技术--->Spring的Jd ...

  9. ASP.NET Excel导入Sql Server数据库(转)

    先看界面图 实现的基本思想: 1,先使用FileUpload控件fuload将Excel文件上传到服务器上得某一个文件夹. 2,使用OleDb将已经上传到服务器上的Excel文件读出来,这里将Exce ...

  10. Apache开启压缩功能

    起源 在一般的web服务器中,都会开启压缩功能,也就是deflate或者是gzip的压缩. 开启压缩功能主要的目的是为了减少传输的带宽,从而当服务器响应给客户端的时候,会大大减少传输的数据,代价就是在 ...