导语
  之前的分享中,了解到了用户身份认证,在说用户认证的时候提到了一个概念就是Realm,在之前的入门分享中提到了,Realm其实就是一个安全数据源,那么怎么样使用这个安全数据源呢?下面就来一起研究一下

文章目录

  • Realm概念
  • Realm接口源码
  • Realm如何使用
    • 单个Realm配置
      • 1、自定Realm的实现com.nihui.shiro.realm.MyRealm类中
      • 2、ini 配置文件指定自定义的Realm
      • 3、测试效果
    • 多个Realm配置
  • Shiro默认提供的Realm
    • org.apache.shiro.realm.text.IniRealm
    • org.apache.shiro.realm.text.PropertiesRealm
    • org.apache.shiro.realm.jdbc.JdbcRealm
    • 自定义Realm实现
  • 总结

Realm概念

  Realm 域,Shiro从Realm获取安全数据(例如用户、角色、权限等)。之前提到SecurityManager需要进行身份验证就必须从Realm中获取到一个合法的用户身份,从而比较用户身份是否合法,同时在SecurityManager获取身份的同时Realm也需要维护一套用户身份用来判断用户是否能执行某项操作。可以把Realm看作是一个DataSource。也就是上面提到的安全数据源。

  在之前的例子中的ini配置文件就可以看做是一个安全数据源

Realm接口源码

public interface Realm {//返回一个唯一的Realm名字String getName();//判断此Realm是否支持此Tokenboolean supports(AuthenticationToken token);//根据Token获取认证信息AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
}

  从上面代码中看到Realm最为重要的一个事情就是根据一个Token获取的认证的信息。

Realm如何使用

  在之前有简单的提到,Realm 使用的时候可以是单个也可以是多个。下面就来分别Realm的不同使用方式。

单个Realm配置

1、自定Realm的实现com.nihui.shiro.realm.MyRealm类中
public class MyRealm implements Realm {public String getName() {return "myrealm";}public boolean supports(AuthenticationToken token) {//仅仅支持一个UsernamePaasswordTokereturn token instanceof UsernamePasswordToken;}public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//获取到用户名和密码String username = (String) token.getPrincipal();String password = new String((char[]) token.getCredentials());if (!"nihui".equals(username)){//用户名错误throw new UnknownAccountException();}if (!"123".equals(password)){//密码错误throw new IncorrectCredentialsException();}//如果身份认证验证成功,返回一个AuthenticationInforeturn new SimpleAuthenticationInfo(username,password,getName());}
}
2、ini 配置文件指定自定义的Realm
# 声明一个realm
myRealm=com.nihui.shiro.realm.MyRealm
# 指定SecurityManager的Realm实现
securityManager.realms=$myRealm
3、测试效果
public class SRealeTest {public static void main(String[] args) {//1、获取SecurityManager工厂,Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");//2、得到一个SecurityManager实例,绑定到SecurityUtilsSecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//得到Subject 以及用户名密码的身份验证TokenSubject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken("nihui","123");// 验证登陆try {subject.login(token);}catch (AuthenticationException e){//身份认证失败}System.out.println(subject.isAuthenticated()); //true表示用户已经登陆//退出操作subject.logout();}
}

多个Realm配置

  多个Realm只需要将配置文件,改为如下的内容分别实现两个Realm就可以了。

# 声明realm
# 声明realm
myRealm1=com.nihui.shiro.realm.realmconfig.MyRealm1
myRealm2=com.nihui.shiro.realm.realmconfig.MyRealm2
# 指定SecurityManager的Realm实现
securityManager.realms=$myRealm1,$myRealm2

  按照SecurityManager会按照realms指定的顺序进行身份认证,按照上面配置文件中指定的顺序,来进行Realm的认证,如果删除了最后指定的securityManager.realms,那么会按照Realm声明的顺序来进行匹配。下面 就来测试一下

Realm1 规则用户名admin,密码123

public class MyRealm1 implements Realm {public String getName() {return "myrealm1";}public boolean supports(AuthenticationToken token) {//仅仅支持一个UsernamePaasswordTokereturn token instanceof UsernamePasswordToken;}public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//获取到用户名和密码String username = (String) token.getPrincipal();String password = new String((char[]) token.getCredentials());if (!"admin".equals(username)){//用户名错误throw new UnknownAccountException();}if (!"123".equals(password)){//密码错误throw new IncorrectCredentialsException();}//如果身份认证验证成功,返回一个AuthenticationInforeturn new SimpleAuthenticationInfo(username,password,getName());}
}

Realm2 规则用户名nihui,密码1234

public class MyRealm2 implements Realm {public String getName() {return "myrealm2";}public boolean supports(AuthenticationToken token) {//仅仅支持一个UsernamePaasswordTokereturn token instanceof UsernamePasswordToken;}public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//获取到用户名和密码String username = (String) token.getPrincipal();String password = new String((char[]) token.getCredentials());if (!"nihui".equals(username)){//用户名错误throw new UnknownAccountException();}if (!"1234".equals(password)){//密码错误throw new IncorrectCredentialsException();}//如果身份认证验证成功,返回一个AuthenticationInforeturn new SimpleAuthenticationInfo(username,password,getName());}
}

测试类

public class MultiRealmTest {public static void main(String[] args) {//1、获取SecurityManager工厂,Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-multi-realm.ini");//2、得到一个SecurityManager实例,绑定到SecurityUtilsSecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//得到Subject 以及用户名密码的身份验证TokenSubject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken("nihui","1234");
//        UsernamePasswordToken token = new UsernamePasswordToken("admin","123");// 验证登陆try {subject.login(token);}catch (AuthenticationException e){//身份认证失败}System.out.println(subject.isAuthenticated()); //true表示用户已经登陆//退出操作subject.logout();}
}

  这个时候如果将配置文件改为如下,会发现它是按照默认顺序进行匹配的并且两个内容都进行了匹配。

# 声明realm
myRealm1=com.nihui.shiro.realm.realmconfig.MyRealm1
myRealm2=com.nihui.shiro.realm.realmconfig.MyRealm2
# 指定SecurityManager的Realm实现
#securityManager.realms=$myRealm1,$myRealm2

  如果将配置文件改为如下的内容效果如何呢?这时候就会发现只有一个nihui的规则被进行了匹配,没有指定的admin的规则则没有被匹配到。

# 声明realm
myRealm1=com.nihui.shiro.realm.realmconfig.MyRealm1
myRealm2=com.nihui.shiro.realm.realmconfig.MyRealm2
# 指定SecurityManager的Realm实现
securityManager.realms=$myRealm1

Shiro默认提供的Realm

  在org.apache.shiro.realm包中提供了默认的一些Realm实现,主要有如下一些内容

  一般情况下在使用扩展的时候只需要继承AuthorizingRealm(授权)就可以了,AuthorizingRealm继承了AuthenticatingRealm(身份验证),同时也间接的继承了CachingRealm(带有缓存的实现)。在上面类中比较重要的几个默认实现。

在实际中的使用

org.apache.shiro.realm.text.IniRealm

  [users]部分指定了用户名密码以及其角色,[roles]部分指定角色信息具体配置可以参考官网IniRealm配置

[users]
nihui=123
test=123
admin=123

org.apache.shiro.realm.text.PropertiesRealm

  通过配置文件的形式来指定。

private static final int DEFAULT_RELOAD_INTERVAL_SECONDS = 10;
private static final String USERNAME_PREFIX = "user.";
private static final String ROLENAME_PREFIX = "role.";
private static final String DEFAULT_RESOURCE_PATH = "classpath:shiro-users.properties";

org.apache.shiro.realm.jdbc.JdbcRealm

  通过SQL查询响应的信息,例如从用户表中查询用户信息,从角色表中查询角色信息。

   /*** The default query used to retrieve account data for the user.*/protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";/*** The default query used to retrieve account data for the user when {@link #saltStyle} is COLUMN.*/protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";/*** The default query used to retrieve the roles that apply to a user.*/protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";/*** The default query used to retrieve permissions that apply to a particular role.*/protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";

自定义Realm实现

  通过继承AuthorizingRealm类来实现自定义的Realm实现。


public class ShiroRealm extends AuthorizingRealm {@Autowiredprivate AdminService adminService;@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//在实际项目中,这里可以根据实际情况做缓存操作。如果没有缓存操作,Shiro有自己的时间隔离机制,2分钟不会重复执行该方法。UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;//获取到用户账号通过用户账号获取到用户信息String account = (String) token.getPrincipal();//        UserAdmin userInfo = adminService.findByUsername(account);Admin userInfo  =adminService.findByUsername(account);if (userInfo==null){throw new UnknownAccountException();}if ("0".equals(userInfo.getStatus().toString())){throw new LockedAccountException();}SecurityUtils.getSubject().getSession().setAttribute("user",userInfo);ByteSource credentialsSalt = ByteSource.Util.bytes(userInfo.getPublic_salt());SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userInfo,userInfo.getPassword(),credentialsSalt,getName());return authenticationInfo;}//这方法是用来做权限认证的方法@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}
}

总结

  通过上面的内容了解到了Realm作为关键数据节点在Shiro中的存在,并且介绍了关于Realm的类继承关系,了解了Realm的存在价值,如何使用Realm。

Shiro系列-Shiro中Realm如何使用相关推荐

  1. Shiro系列-Shiro的怎么进行授权操作

    导语   之前的分享中,提到了Shiro的简单介绍,知道了Shiro是什么,作用是什么,以及用户身份认证.那么完成用户身份认证之后又需要干点啥呢?在用户身份认证之后接下来就要要根据用户身份角色信息进行 ...

  2. Shiro系列-Shiro如何实现身份验证

    导语   下面就来按照顺序依次介绍一下Shiro的使用场景,场景代码后续会放到GitHub上面希望大家可以多多支持.首先先来介绍一下Shiro的身份认证. 文章目录 Shiro身份验证 入门小例子 环 ...

  3. Shiro系列-Shiro简介

    导语   Apache Shiro是一个Java安全框架,现在在很多的场景下使用Shiro的人越来越多.因为它与Spring Security 相比较来说相对比较简单,从功能上来讲也没有Spring ...

  4. (六) shiro在web中自定义Realm

    1 前言 : shiro代码参考java1234网站<一头扎进shiro>视频敲出来的,原理这些请参视频 , 点击 下载源码 点击 下载数据库 2 项目结构图 3 代码 MyRealm.j ...

  5. Shiro系列(三)--- Shiro身份验证和授权

    继续我们shiro系列博客相关的学习笔记,各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟.多谢! 目录 身份验证 示例 创建SecurityManager ...

  6. shiro系列一、认识shiro

    Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大 ...

  7. 解决shiro重定向URL中出现sessionID的情况localhost:8080/toLogin;jsessionid=D5C1EE61B97EE2D7098F58A837B82BD4

    先直接说解决办法: 直接在shiro配置类中添加一下代码就能解决: @Configuration public class MyShiroConfig {/*** 解决shiro的URL中出现sess ...

  8. Shiro验证策略-shiro自定义实现Realm来实现身份验证-shiro散列加密算法-shiro授权-shiro自定义Realm实现授权

    Shiro验证策略 Authentication Strategy:认证策略,在shiro中有三种认证策略: AtleastOneSuccessfulStrategy[默认] 如果一个或多个Realm ...

  9. 【若依(ruoyi)】 Shiro 向 ShiroFilterFactoryBean 中添加自定义过滤器

    前言 若依(ruoyi): v4.3 shiro: 1.5.3 遇坑:shiro 自定义过滤器执行异常,无法排除已允许匿名访问的功能/URL 需求 使用 ruoyi 开发 restful 接口.因此, ...

最新文章

  1. 终端安全工具 gartner 排名
  2. Windows Server 2003 (64bit)操作系统上部署 ArcSDE 9.2
  3. 使用jQuery实现图片懒加载原理
  4. .net中的mapinfo开发:准备(一)
  5. 原创:PHP内核研究:HASH表和变量
  6. mysql最大连接数合理值_MySQL服务器最大连接数的合理设置
  7. 盘点那些有“数学味”的建筑
  8. 第 1-1 课:Java 程序是如何执行的?
  9. 【TensorFlow系列二】经典损失函数(交叉熵、均方差)
  10. 为Windows Phone SDK 模拟器安装应用
  11. 小程序入门学习09--云开发02
  12. hdu 4421(枚举+2-sat)
  13. FP-growth发现频繁项集
  14. 微信小程序快捷键和windows快捷键
  15. linux+开机启动sshd_Linux sshd服务自动启动
  16. 【JS】V8 引擎原理
  17. Shell脚本切换root用户或获取root权限
  18. 2021年施工员-装饰方向-岗位技能(施工员)考试报名及施工员-装饰方向-岗位技能(施工员)找解析
  19. 3d建模电脑配置要求
  20. 有什么好用的在线图表制作网站吗?试试这个吧

热门文章

  1. python统计词频_python统计词频
  2. AlipaySDK Cocoapods支持
  3. Java下List使用subList实现分页获取
  4. 数值的整数次方(剑指offer面试题11)
  5. 解决/usr/bin/ld: cannot find -lxxx
  6. 算法:数组中的逆序对
  7. 柏林纪行(中):Node.js Collaboration Summit
  8. 即时通讯开发----回音消除技术
  9. SQL Server批量插入数据
  10. Quartz 2 定时任务(一):基本使用指南