首先还是Realm的接口设计图:
这里只来说明SimpleAccountRealm和JdbcRealm的实现。
首先是SimpleAccountRealm不用关心数据的具体来源,只提供了与上层的交互,即实现了AuthenticatingRealm遗留的AuthenticationInfo doGetAuthenticationInfo和AuthorizingRealm遗留的AuthorizationInfo doGetAuthorizationInfo。
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
SimpleAccountRealm内部有四个属性,Map<String, SimpleAccount> users:用于存放用户账号信息,Map<String, SimpleRole> roles用于存放角色名的信息。这两个都是各种配置的最终归属存储地。
ReadWriteLock USERS_LOCK:由于这些配置信息,一般不会去修改,大部分时间用于查询,所以要使用读写锁。一般的synchronized同步,不管你是读还是写,都要进行等待。写与写需要进行同步,写与读也要进行同步,但读与读却并不需要进行同步,所以对于那些经常读的场景,要使用读写锁ReadWriteLock 来提升性能。ReadWriteLock ROLES_LOCK同理。
有了以上数据源,实现父类的遗留的方法就比较简单了。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
代码就很简单了,就是从users中取出相应的用户数据。接下来要分析清几个概念:
AuthorizationInfo、AuthenticationInfo、SimpleAccount、SimpleRole、PrincipalCollection。
PrincipalCollection:看下文档介绍
引用
/**
* A collection of all principals associated with a corresponding { @link Subject Subject}. A <em>principal</em> is
* just a security term for an identifying attribute, such as a username or user id or social security number or
* anything else that can be considered an 'identifying' attribute for a { @code Subject}.
* <p/>
* A PrincipalCollection organizes its internal principals based on the { @code Realm} where they came from when the
* Subject was first created. To obtain the principal(s) for a specific Realm, see the { @link #fromRealm} method. You
* can also see which realms contributed to this collection via the { @link #getRealmNames() getRealmNames()} method.
*/
一个principal仅仅是Subject的一个标识而已,如可以是用户名,用户id等。PrincipalCollection则是这些属性的集合。每个用户属性可以来自不同的Realm。Collection fromRealm(String realmName)可以获取某个Realm的所有用户属性。Set<String> getRealmNames()可以获取到与Subject关联的用户的属性来自于哪些Realm。
Object getPrimaryPrincipal():主要是用于获取唯一标示,如UUID、username等。
接口如下:
1 2 3 4 5 6 |
|
我们知道每一个标示都有所属的realm,所以再添加的时候,要带上realmName。
SimplePrincipalCollection:
1 |
|
一个重要的数据集合,key是realm的name,value是principal集合。
这个接口分支一直在强调,每个principal都是有所属的realm的。
PrincipalMap:我这一块没有搞明白,先放下。
AuthenticationInfo 它是含有用户和密码信息的地方:
1 2 3 4 |
|
AuthorizationInfo :存放用户权限的地方
1 2 3 4 5 |
|
类图如下:
MergableAuthenticationInfo 意味着AuthenticationInfo可以进行合并:
1 2 3 |
|
SaltedAuthenticationInfo 主要用于密码匹配,后续文章专门说明:
1 2 3 |
|
SimpleAuthenticationInfo:存储了三个重要的属性:
1 2 3 |
|
然后就是实现了MergableAuthenticationInfo 接口,可以进行合并,这里的合并在第一篇文章中Realm认证中提到过:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
|
主要分principals、credentialsSalt 和credentials三项的合并,代码也和简单。
SimpleAuthorizationInfo:存放了认证用户的角色和用户权限。
1 2 3 |
|
最重要的就是SimpleAccount:
1 2 3 4 5 6 |
|
它有SimpleAuthenticationInfo 、SimpleAuthorizationInfo ,所以是用户认证信息和权限信息的汇总。
还有两个属性locked和credentialsExpired,用来表示用户的锁定和密码过期的状态。
至此整个SimpleAccount便介绍完了。
回到SimpleAccountRealm,SimpleAccountRealm已经拥有Map<String, SimpleAccount> users和Map<String, SimpleRole> roles数据了,但是这些数据是怎么产生的呢?这就需要交给它的子类TextConfigurationRealm来完成:
1 2 |
|
仅仅两个字符串包含了所有的用户和角色的配置总来源。所以TextConfigurationRealm主要就是对这两个字符串的解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
再通过PermissionResolver将字符串形式的权限转化成Permission对象,知道大致情况了,就可以了,不需要每一步都弄清楚。
TextConfigurationRealm主要用于解析两个配置字符串,这两个配置字符串的产生则继续交给子类来完成。IniRealm则是通过ini配置文件来产生这两个字符串,PropertiesRealm则是通过properties文件来产生这两个字符串。
至此,SimpleAccountRealm这一路就大致走通了,接下来就是另一条路JdbcRealm了。
1 2 3 4 5 6 7 |
|
首先是含有这几个默认的sql和DataSource dataSource,用于从数据库中获取相应的用户、角色、权限等数据。
根据上一篇文章我们知道JdbcRealm 要实现AuthenticatingRealm遗留的AuthenticationInfo doGetAuthenticationInfo和AuthorizingRealm遗留的AuthorizationInfo doGetAuthorizationInfo。下面就看看是怎么来实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
|
代码很简单就不再一一细说。再看下doGetAuthorizationInfo是怎么实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
第一步先根据PrincipalCollection 来获取用户名,第二步根据用户名来获取角色,第三部根据角色和用户名来获取权限。后两步都是执行简单的sql,不再说,看下如何由PrincipalCollection 获取用户名,该方法定义在CachingRealm中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
两种情况,首先是获取当前Realm的Principals,如果有取其第一个。如果没有,则调用getPrimaryPrincipal()方法。然后看下JdbcRealm的一个简单使用:
如果默认按照JdbcRealm的sql来作为数据库的查询来说,建表如下:
users表:
1 2 3 4 5 6 7 8 |
|
user_roles表:
1 2 3 4 5 6 |
|
roles_permissions表:
1 2 3 4 5 6 |
|
文章最后会给出数据库sql文件。
然后就是配置ini文件:
1 2 3 4 5 6 7 8 9 10 11 |
|
使用的dataSource是c3p0的dataSource,mysql驱动也是必然不能少的,所以maven中要加入依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
为了输出方便代码更改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
对于lg用户,在数据库中它是有两个角色的,role1和role2。所以结果为true、true、false。
1 2 3 |
|
OK,通过。最后附上JdbcRealm的使用例子。