自定义Realm实现身份认证

先来看下Realm的类继承关系:

Realm接口有三个方法,最重要的是第三个方法:

a) String getName():返回此realm的名字

b) boolean supports(AuthenticationToken token) :好像是说,判断是哪个类型的token

c)* AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException:获得认证信息

===========================================================================

1,jdbcRealm已经实现了从数据库中获取用户的验证信息,但是jdbcRealm灵活性太差。如果要实现自己的一些特殊应用时将不能支持。此时可通过自定义Realm来实现身份的认证功能。

2,在Realm接口中,在接口中最重要的是方法是getAuthenticationInfo(token) ,可以根据token获得认证信息。

由上图可知,Shiro内容实现了一系列的realm。这些不同的Realm实现类提供了不同的功能,最重要的是:

 a)AuthenticatingRealm:AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)实现了获取身份信息的功能

 b)AuthorizingRealm:AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals)实现了获取权限信息的功能。

由于AuthorizingRealm是AuthenticatingRealm的子类,所以,通常自定义Realm需要继承AuthorizingRealm,这样既可以提供了身份认证的自定义方法,也可以实现授权的自定义方法。

====================================================================================

实验:

1,新建maven项目,添加依赖:

 <dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency> <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency> <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency> <dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.31</version>
</dependency>

2,项目结构

先来说说散列算法吧,因为里边要用到shiro提供的加密算法,以MD5为例。shiro提供了好多个散列加密算法:(此段有待查阅资料学习补充)

Md5例子,shiro加密可以加盐,还可以迭代多次进行加密,就是加密之后在加密。

public class Md5Demo {

    public static void main(String[] args) {
String pwd = "1111"; //使用md5加密
Md5Hash md5 = new Md5Hash(pwd);
// System.out.println("123进行md5加密----"+md5.toString());
//加盐
md5 = new Md5Hash(pwd,"lhy");
// System.out.println("1111 md5加密加盐---"+md5.toString());
//迭代加密
md5 = new Md5Hash(pwd, "lhy", 2);
System.out.println("123 md5加盐迭代---"+md5.toString()); }
}

3,数据库表:

4,ini配置文件:

[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#设置散列算法
credentialsMatcher.hashAlgorithmName=md5
#设置散列次数
credentialsMatcher.hashIterations=2
userRealm=com.lhy.realm.UserRealm
#将凭证匹配器设置到realm
userRealm.credentialsMatcher=$credentialsMatcher
securityManager.realm=$userRealm

自定义userRealm继承了AuthorizingRealm,AuthorizingRealm 继承了AuthenticatingRealm,在AuthenticatingRealm中,有setCredentialsMatcher(matcher);方法,

用来设置凭证的匹配器。凭证匹配器CredentialsMatcher是个接口,我们用其实现类HashedCredentialsMatcher。HashedCredentialsMatcher中有setHashAlgorithmName 方法用来设置算法名字,setHashIterations(int hashIterations)方法用来设置加密的迭代次数(看源码可知)。

log4j:

log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

5,userRealm类:

/**
* 自定义Realm实现,该Realm类提供了两个方法:
* 1,doGetAuthenticationInfo:获取认证信息
* 2,doGetAuthorizationInfo:获取权限信息
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm{ //realm接口的方法
@Override
public String getName() {
return "userRealm";
} //完成身份认证并返回认证信息
//如果身份认证失败,返回null
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//获取用户输入的用户名
String username = (String)token.getPrincipal();//获取身份信息
System.out.println("username----"+username);
//实际开发是调用service根据用户名去数据库查对应的密码
//假设获取的密码是1111
// String password = "1111";
String password ="cda480d3c0ffa424905444e760e7447d";
String salt = "lhy"; //将数据库中获取的进行封装,注意盐值的类型是ByteSource
//参数:用户名,加密后的密码,盐值,realm名字
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, ByteSource.Util.bytes(salt), getName());
return info;
} //授权的信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) { return null;
} }

测试程序,步骤有点简单,上述代码中的password是由字符串"niubei" 根据盐lhy 迭代2次后的结果,用来模拟从数据库中取出的加密后的密码,

测试代码:

public class userRealmDemo { 

    public static void main(String[] args) {
//1,创建SecurityManager工厂 读取shiro配置文件
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2 通过securityManager工厂获取SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//3 将SecurityManager 对象设置到运行环境
SecurityUtils.setSecurityManager(securityManager);
//4 通过SecurityUtils获取主体subject
Subject subject = SecurityUtils.getSubject();
try {
//5.假设登录名是zhangsan 密码是1111
UsernamePasswordToken token = new UsernamePasswordToken("niubei","1111");
//6,登录,进行用户身验证
subject.login(token);
//通过subject判断用户是否通过验证
if(subject.isAuthenticated()){
System.out.println("用户登录成功!");
}
} catch (UnknownAccountException e) {
System.out.println("用户名或密码错误!");
e.printStackTrace();
}catch (IncorrectCredentialsException e) {
System.out.println("用户名或密码错误!");
e.printStackTrace();
}
//其他异常处理。。。
//7 退出
subject.logout();
}
}

输出:

username----niubei
2017-03-26 19:02:04,487 INFO [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Enabling session validation scheduler...
用户登录成功!

测试成功。。。

注意,刚开始我用的shiro版本是1.1.0,userRealm代码中 ByteSource.Util.bytes(salt) 报错,ByteSource接口根本没有Util类,百度了一下,看了这个接口的源代码才知道,这个Util类从shiro的1.2才开始有的,无语了。

shiro学习笔记_0400_自定义realm实现身份认证的更多相关文章

  1. shiro学习笔记_0600_自定义realm实现授权

    博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 ...

  2. Shiro学习笔记六(自定义Reaml-使用数据库设置 user roles permissions)

    1.工程目录 pom文件还和以前设置的一样就是添加了一个数据库驱动, <dependencies> <dependency> <groupId>junit</ ...

  3. Shiro学习笔记总结,附加" 身份认证 "源码案例(一)

    Shiro学习笔记总结 内容介绍: 一.Shiro介绍 二.subject认证主体 三.身份认证流程 四.Realm & JDBC reaml介绍 五.Shiro.ini配置介绍 六.源码案例 ...

  4. Shiro学习笔记(5)——web集成

    Web集成 shiro配置文件shiroini 界面 webxml最关键 Servlet 測试 基于 Basic 的拦截器身份验证 Web集成 大多数情况.web项目都会集成spring.shiro在 ...

  5. [转载]SharePoint 2013搜索学习笔记之自定义结果源

    搜索中心新建好之后在搜索结果页上会默认有所有内容,人员,对话,视频这四个结果分类,每个分类会返回指定范围的搜索结果,这里我再添加了部门日志结果分类,搜索这个分类只会返回部门日志内容类型的搜索结果,要实 ...

  6. Hadoop学习笔记—5.自定义类型处理手机上网日志

    转载自http://www.cnblogs.com/edisonchou/p/4288737.html Hadoop学习笔记—5.自定义类型处理手机上网日志 一.测试数据:手机上网日志 1.1 关于这 ...

  7. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  8. SpringBoot学习笔记:自定义拦截器

    SpringBoot学习笔记:自定义拦截器 快速开始 拦截器类似于过滤器,但是拦截器提供更精细的的控制能力,它可以在一个请求过程中的两个节点进行拦截: 在请求发送到Controller之前 在响应发送 ...

  9. 【转】权限管理学习 一、ASP.NET Forms身份认证

    [转]权限管理学习 一.ASP.NET Forms身份认证 说明:本文示例使用的VS2017和MVC5. 系统无论大小.牛逼或屌丝,一般都离不开注册.登录.那么接下来我们就来分析下用户身份认证. 简单 ...

随机推荐

  1. javascript编码规范[原创]

    一些命名规范书或js书命名规范章节,喜欢将命名规范跟语法混在一块例如: 1.使用“var”定义.初始化变量防止产生全局变量,多变量一块定义使用“,”(本身这种方式就很有争议). 2.结尾必加“;”防止 ...

  2. RSA加密解密总结

    简单的控制台程序 #include"stdafx.h" #include <math.h> #include<string.h> /*/求解密密钥d的函数( ...

  3. java并发编程实战:第七章----取消与关闭

    Java没有提供任何机制来安全地终止线程(虽然Thread.stop和suspend方法提供了这样的机制,但由于存在缺陷,因此应该避免使用 中断:一种协作机制,能够使一个线程终止另一个线程的当前工作 ...

  4. DRBD+Heartbeat实现自动切换

    1>HeartBeat介绍 Heartbeat 项目是 Linux-HA 工程的一个组成部分,它实现了一个高可用集群系统.心跳服务和集群通信是高可用集群的两个关键组件,在 Heartbeat 项 ...

  5. 简明的sql优化

    网上关于SQL优化的教程很多,但是比较杂乱.近日有空整理了一下,写出来跟大家分享一下,其中有错误和不足的地方,还请大家纠正补充. 这篇文章我花费了大量的时间查找资料.修改.排版,希望大家阅读之后,感觉 ...

  6. Linq使用中的ToList注意事项

    在使用Linq时,如果查询逻辑太复杂,可以拆分为多个Linq查询,下一个Linq在上一个Linq查询的结果上继续操作,这样逻辑清晰,又不会出错.但在使用ToList的时候需要注意,最常见碰到的错误是: ...

  7. [Oracle]Oracle部分函数

    1.nvl(a,b) 若a为null,则b 2.to_char(date,'YY-MM-DD') 按格式将date类型转为字符串 to_date('1999/1/1','YY-MM-DD') 将字符串 ...

  8. 域名通过infopath访问webservice出现401错误

    解决办法: 跟服务器有关,需要再每台服务器进行以下配置 New-ItemProperty HKLM:\System\CurrentControlSet\Control\Lsa -Name " ...

  9. 【总结】 BZOJ1000~1099板刷计划

    Tham又布置了一大堆题目,但是因为我TCL完全不会做,所以只能切切BZOJ的题目,划划水,要不是xz的面子大,我就已经被赶出了CJ信息组了QwQ(聂已己是神仙!) 1000 A+B这种入门题就不用写 ...

  10. NOIP2013PUZZLE

    #include<cstdio> #include<cstring> #define MIN(A,B) (A)<(B)?(A):(B) using namespace s ...