Shiro系列-Shiro中Realm如何使用

 2023-09-15 阅读 23 评论 0

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

导语
  之前的分享中,了解到了用户身份认证,在说用户认证的时候提到了一个概念就是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接口源码

shiro使用详解,在这里插入图片描述

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

shiro命令执行,  [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。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/60440.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息