在上一篇介绍SecurityManager的初始化过程中,也有realm的粗略介绍。 
realm的概念在安全领域随处可见: 
各种中间件的realm、spring security的realm、shiro的realm。。。如下: 
tomcat的realm: http://tomcat.apache.org/tomcat-7.0-doc/realm-howto.html 
weblogic的realm:http://edocs.weblogicfans.net/wls/docs92/secintro/realm_chap.html 
spring security的realm http://www.oschina.net/translate/spring-security-basic-authentication?lang=eng 
tomcat官网对realm的定义是这样的:

A Realm is a "database" of usernames and passwords that identify valid users of a web application (or set of web applications), plus an enumeration of the list of roles associated with each valid user. You can think of roles as similar to groups in Unix-like operating systems, because access to specific web application resources is granted to all users possessing a particular role (rather than enumerating the list of associated usernames). A particular user can have any number of roles associated with their username.

我个人理解realm相当于管理账号密码、角色、权限的仓库。有异议的,欢迎一起讨论。 
原谅我的啰嗦,先进入正题。 
Shiro的realm类图如下:

由图可见,Realm主要还是认证、授权服务,并提供cache支持。 
shiro提供了几种realm可供项目选择,一般项目中比较常用的应该是JdbcRealm,运行测试用例一般使用IniRealm。 
开涛在讲解身份验证的章节中演示了两种realm的方式(ini、jdbc) 
http://jinnianshilongnian.iteye.com/blog/2019547 
一、Ini方式的realm:

从图中可看出,shiro对于通过文本方式定义账号、权限提供了Ini、Properties两种方式。SimpleAccountRealm类的users、roles集合分别用来保存账号、权限信息。 
还记得在前一篇介绍SecurityManager初始化中,关于realm的创建了么?

没错,就是这里。根据ini配置中的users、roles段落来解析成IniRealm的对象实例。 
下面,简单跟踪一下代码吧:

//IniRealm构造函数会调用此方法完成解析操作
private void processDefinitions(Ini ini) {
if (CollectionUtils.isEmpty(ini)) {
log.warn("{} defined, but the ini instance is null or empty.", getClass().getSimpleName());
return;
} Ini.Section rolesSection = ini.getSection(ROLES_SECTION_NAME);
if (!CollectionUtils.isEmpty(rolesSection)) {
log.debug("Discovered the [{}] section. Processing...", ROLES_SECTION_NAME);
//解析roles段落交给父类完成
processRoleDefinitions(rolesSection);
} Ini.Section usersSection = ini.getSection(USERS_SECTION_NAME);
if (!CollectionUtils.isEmpty(usersSection)) {
log.debug("Discovered the [{}] section. Processing...", USERS_SECTION_NAME);
//解析users段落交给父类完成
processUserDefinitions(usersSection);
} else {
......
}
}

niRealm的父类TextConfigurationRealm根据子类的users、roles配置完成解析操作

//解析roles,并构造SimpleRole对象
protected void processRoleDefinitions(Map<String, String> roleDefs) {
if (roleDefs == null || roleDefs.isEmpty()) {
return;
}
for (String rolename : roleDefs.keySet()) {
String value = roleDefs.get(rolename); SimpleRole role = getRole(rolename);
if (role == null) {
role = new SimpleRole(rolename);
add(role);
} Set<Permission> permissions = PermissionUtils.resolveDelimitedPermissions(value, getPermissionResolver());
role.setPermissions(permissions);
}
}
//解析roles,并构造SimpleRole对象
protected void processRoleDefinitions(Map<String, String> roleDefs) {
if (roleDefs == null || roleDefs.isEmpty()) {
return;
}
for (String rolename : roleDefs.keySet()) {
String value = roleDefs.get(rolename); SimpleRole role = getRole(rolename);
if (role == null) {
role = new SimpleRole(rolename);
add(role);
} Set<Permission> permissions = PermissionUtils.resolveDelimitedPermissions(value, getPermissionResolver());
role.setPermissions(permissions);
}
}
//解析users,并构造SimpleAccount对象
protected void processUserDefinitions(Map<String, String> userDefs) {
if (userDefs == null || userDefs.isEmpty()) {
return;
}
for (String username : userDefs.keySet()) { String value = userDefs.get(username); String[] passwordAndRolesArray = StringUtils.split(value); String password = passwordAndRolesArray[]; SimpleAccount account = getUser(username);
if (account == null) {
account = new SimpleAccount(username, password, getName());
add(account);
}
account.setCredentials(password); if (passwordAndRolesArray.length > ) {
for (int i = ; i < passwordAndRolesArray.length; i++) {
String rolename = passwordAndRolesArray[i];
account.addRole(rolename); SimpleRole role = getRole(rolename);
if (role != null) {
account.addObjectPermissions(role.getPermissions());
}
}
} else {
account.setRoles(null);
}
}
}

二、Jdbc方式的realm:

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro
dataSource.username=root
dataSource.password=root
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm

由于shiro支持在ini中配置依赖注入,那么JdbcRealm中的sql信息也是可配置的。

jdbcRealm.authenticationQuery=用户查询
jdbcRealm.userRolesQuery=角色查询
jdbcRealm.permissionsQuery=权限查询

当然,如果不习惯这种方式,可以直接自定义Realm,并继承自AuthorizingRealm或者JdbcRealm都可以。 
JdbcRealm通过查询数据库的认证实体、角色、权限,构造的对象分别是:SimpleAuthenticationInfo、SimpleAuthorizationInfo。 
实际上,IniRealm方式构造的SimpleAccount、SimpleRole与JdbcRealm方式构造的SimpleAuthenticationInfo、SimpleAuthorizationInfo一一对应,且都实现认证接口AuthenticationInfo、授权接口AuthorizationInfo。关于更详细的讲解放在后面的认证、授权部分。 
三、RealmFactory: 
Shiro不仅支持Realm类型,还支持RealmFactory类型,在初始化的时候,如果配置中存在RealmFactory实现类,则直接调用其Collection<Realm> getRealms()方法。 
该方式在多个realm的情况下很实用。 
四、与Spring Security的比较: 
Spring Security的Realm仅仅是用在basic认证方式。 
Shiro的realm与Spring Security的UserDetailsService非常相似。但是命名确非常迷糊,下面进一步分析: 
先看UserDetailsService接口定义:

//根据用户名称获取UserDetails
public interface UserDetailsService {
UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException;
}

UserDetails接口定义:

public interface UserDetails extends Serializable {
//获取授权的集合
Collection<GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}

由此可看出,Spring Security的UserDetailsService获取的UserDetails已经拥有了授权信息。只是从接口命名中无法得知。 
而Shiro的realm是把职责分解了,层次更清晰些。 
后续在分析shiro的过程中,会增加与SpringSecurity的比较。

Shiro源码分析-初始化-Realm的更多相关文章

  1. Shiro源码分析之SecurityManager对象获取

    目录 SecurityManager获取过程 1.SecurityManager接口介绍 2.SecurityManager实例化时序图 3.源码分析 4.总结 @   上篇文章Shiro源码分析之获 ...

  2. Shiro 源码分析

    http://my.oschina.net/huangyong/blog/215153 Shiro 是一个非常优秀的开源项目,源码非常值得学习与研究. 我想尝试做一次 不一样 的源码分析:源码分析不再 ...

  3. Shiro源码分析

    1.入口类:AbstractAuthenticator 用户输入的登录信息经过其authenticate方法: public final AuthenticationInfo authenticate ...

  4. linux调度器源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 上期文章linux调度器源码分析 - 概述(一)已经把调度器相关的数据结构介绍了一遍,本篇着重通过代码说明 ...

  5. Linux 内核调度器源码分析 - 初始化

    导语 上篇系列文 混部之殇-论云原生资源隔离技术之CPU隔离(一) 介绍了云原生混部场景中CPU资源隔离核心技术:内核调度器,本系列文章<Linux内核调度器源码分析>将从源码的角度剖析内 ...

  6. linux中断源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 本篇文章主要讲述源码中是如何对中断进行一系列的初始化的. 回顾 在上一篇概述中,介绍了几个对于中断来说非常重要的 ...

  7. struts2源码分析-初始化流程

    这一篇文章主要是记录struts.xml的初始化,还原struts2.xml的初始化流程.源码依据struts2-2.3.16.3版本. struts2初始化入口,位于web.xml中: <fi ...

  8. Shiro源码分析之Subject和SecurityManager

    Subject 毫无疑问,Subject是Shiro最重要的一个概念. “Subject”只是一个安全术语,意味着应用程序用户的特定于安全性的“视图”.Shiro Subject实例代表单个应用程序用 ...

  9. wifidog源码分析 - 初始化阶段

    Wifidog是一个linux下开源的认证网关软件,它主要用于配合认证服务器实现无线路由器的认证放行功能. wifidog是一个后台的服务程序,可以通过wdctrl命令对wifidog主程序进行控制. ...

随机推荐

  1. HDU4044 GeoDefense(有点不一样的树上背包)

    题目大概说一棵n个结点的树,每个结点都可以安装某一规格的一个塔,塔有价格和能量两个属性.现在一个敌人从1点出发但不知道他会怎么走,如果他经过一个结点的塔那他就会被塔攻击失去塔能量的HP,如果HP小于等 ...

  2. ZOJ2332 Gems(最大流)

    题目大概说,alsomagic有宝石,宝石有颜色和形状两个属性:他有一种法力可以将某些颜色形状的宝石转化成另一种颜色形状的宝石:他的女朋友对各个颜色都有一定的容忍数量,而他自己也对各个形状都有一定的容 ...

  3. 【wikioi】1191 数轴染色(线段树+水题)

    http://wikioi.com/problem/1191/ 太水的线段树了,敲了10分钟就敲完了,但是听说还有一种并查集的做法?不明觉厉. #include <cstdio> #inc ...

  4. eWebeditor编辑器上传图片路径错误解决方法[疑难杂症]【转,作者:unvs】

    做了一个多版本的网站,后台用的编辑器是eWebeditor,NET版,后面发现上传图片或者文件之后,路径错误无法显示,必须手工修改才行.. 为了更清楚的说明问题,我下面会说的比较详细,首先是网站文件框 ...

  5. sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"问题解决

    安装一个软件时,遇到这个问题sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" 上网 ...

  6. MemPool

    腾讯笔试题,设计内存池,alloc和free都是O(1). 和LRUCache类似,这里用了一个list表示可用的空间,用一个map来记录这块内存是否已分配,这样free的时候才可能O(1). cla ...

  7. Android消息处理机制

    Android消息处理机制 Android应用程序消息处理机制(深入到native,实际由管道实现-pipe&epoll)

  8. POJ 3041 匈牙利算法模板题

    一开始预习是百度的算法 然后学习了一下 然后找到了学长的ppt 又学习了一下.. 发现..居然不一样... 找了模板题试了试..百度的不好用 反正就是wa了..果然还是应当跟着学长混.. 图两边的点分 ...

  9. 《Java核心技术卷一》笔记 多线程

    有时,我们需要在一个程序中同时并行的处理多个任务,如播放器一边要播放音乐同时还要不断更新画面显示,或者是一边执行耗时任务,UI还能一边继续响应各种事件.还有的时候,一个任务需要很长时间才能完成,如果分 ...

  10. PHP 错误与异常 笔记与总结(16 )自定义异常处理器

    可以使用自定义异常处理器来处理所有未捕获的异常(没有用 try/catch 捕获的异常). set_exception_handler():设置一个用户定义的异常处理函数,当一个未捕获的异常发生时所调 ...