- 浏览: 232899 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
shuhucy:
必须赞啊,源码理解的很深,解决一个困扰两天的问题
Spring AOP源码分析(八)SpringAOP要注意的地方 -
sealinesu:
精彩
Spring事务源码分析(一)Spring事务入门 -
whlt20090509:
"WEB-INF/view目录下有一个简单的hell ...
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门 -
hai0378:
兄台 算我一个,最近在研究dubbo motan 及 zk ...
ZooKeeper源码研究寻求小伙伴 -
zpkbtzmbw:
看懂了,原理
SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter
首先还是Realm的接口设计图:
这里只来说明SimpleAccountRealm和JdbcRealm的实现。
首先是SimpleAccountRealm不用关心数据的具体来源,只提供了与上层的交互,即实现了AuthenticatingRealm遗留的AuthenticationInfo doGetAuthenticationInfo和AuthorizingRealm遗留的AuthorizationInfo doGetAuthorizationInfo。
如下:
SimpleAccountRealm内部有四个属性,Map<String, SimpleAccount> users:用于存放用户账号信息,Map<String, SimpleRole> roles用于存放角色名的信息。这两个都是各种配置的最终归属存储地。
ReadWriteLock USERS_LOCK:由于这些配置信息,一般不会去修改,大部分时间用于查询,所以要使用读写锁。一般的synchronized同步,不管你是读还是写,都要进行等待。写与写需要进行同步,写与读也要进行同步,但读与读却并不需要进行同步,所以对于那些经常读的场景,要使用读写锁ReadWriteLock 来提升性能。ReadWriteLock ROLES_LOCK同理。
有了以上数据源,实现父类的遗留的方法就比较简单了。如下:
代码就很简单了,就是从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等。
接口如下:
MutablePrincipalCollection如下:
我们知道每一个标示都有所属的realm,所以再添加的时候,要带上realmName。
SimplePrincipalCollection:
一个重要的数据集合,key是realm的name,value是principal集合。
这个接口分支一直在强调,每个principal都是有所属的realm的。
PrincipalMap:我这一块没有搞明白,先放下。
AuthenticationInfo 它是含有用户和密码信息的地方:
AuthorizationInfo :存放用户权限的地方
类图如下:
MergableAuthenticationInfo 意味着AuthenticationInfo可以进行合并:
SaltedAuthenticationInfo 主要用于密码匹配,后续文章专门说明:
SimpleAuthenticationInfo:存储了三个重要的属性:
然后就是实现了MergableAuthenticationInfo 接口,可以进行合并,这里的合并在第一篇文章中Realm认证中提到过:
主要分principals、credentialsSalt 和credentials三项的合并,代码也和简单。
SimpleAuthorizationInfo:存放了认证用户的角色和用户权限。
最重要的就是SimpleAccount:
它有SimpleAuthenticationInfo 、SimpleAuthorizationInfo ,所以是用户认证信息和权限信息的汇总。
还有两个属性locked和credentialsExpired,用来表示用户的锁定和密码过期的状态。
至此整个SimpleAccount便介绍完了。
回到SimpleAccountRealm,SimpleAccountRealm已经拥有Map<String, SimpleAccount> users和Map<String, SimpleRole> roles数据了,但是这些数据是怎么产生的呢?这就需要交给它的子类TextConfigurationRealm来完成:
仅仅两个字符串包含了所有的用户和角色的配置总来源。所以TextConfigurationRealm主要就是对这两个字符串的解析:
再通过PermissionResolver将字符串形式的权限转化成Permission对象,知道大致情况了,就可以了,不需要每一步都弄清楚。
TextConfigurationRealm主要用于解析两个配置字符串,这两个配置字符串的产生则继续交给子类来完成。IniRealm则是通过ini配置文件来产生这两个字符串,PropertiesRealm则是通过properties文件来产生这两个字符串。
至此,SimpleAccountRealm这一路就大致走通了,接下来就是另一条路JdbcRealm了。
首先是含有这几个默认的sql和DataSource dataSource,用于从数据库中获取相应的用户、角色、权限等数据。
根据上一篇文章我们知道JdbcRealm 要实现AuthenticatingRealm遗留的AuthenticationInfo doGetAuthenticationInfo和AuthorizingRealm遗留的AuthorizationInfo doGetAuthorizationInfo。下面就看看是怎么来实现的:
代码很简单就不再一一细说。再看下doGetAuthorizationInfo是怎么实现的:
第一步先根据PrincipalCollection 来获取用户名,第二步根据用户名来获取角色,第三部根据角色和用户名来获取权限。后两步都是执行简单的sql,不再说,看下如何由PrincipalCollection 获取用户名,该方法定义在CachingRealm中:
两种情况,首先是获取当前Realm的Principals,如果有取其第一个。如果没有,则调用getPrimaryPrincipal()方法。然后看下JdbcRealm的一个简单使用:
如果默认按照JdbcRealm的sql来作为数据库的查询来说,建表如下:
users表:
user_roles表:
roles_permissions表:
文章最后会给出数据库sql文件。
然后就是配置ini文件:
使用的dataSource是c3p0的dataSource,mysql驱动也是必然不能少的,所以maven中要加入依赖:
为了输出方便代码更改为:
对于lg用户,在数据库中它是有两个角色的,role1和role2。所以结果为true、true、false。
OK,通过。最后附上JdbcRealm的使用例子。
作者:乒乓狂魔
这里只来说明SimpleAccountRealm和JdbcRealm的实现。
首先是SimpleAccountRealm不用关心数据的具体来源,只提供了与上层的交互,即实现了AuthenticatingRealm遗留的AuthenticationInfo doGetAuthenticationInfo和AuthorizingRealm遗留的AuthorizationInfo doGetAuthorizationInfo。
如下:
protected final Map<String, SimpleAccount> users; //username-to-SimpleAccount protected final Map<String, SimpleRole> roles; //roleName-to-SimpleRole protected final ReadWriteLock USERS_LOCK; protected final ReadWriteLock ROLES_LOCK; public SimpleAccountRealm() { this.users = new LinkedHashMap<String, SimpleAccount>(); this.roles = new LinkedHashMap<String, SimpleRole>(); USERS_LOCK = new ReentrantReadWriteLock(); ROLES_LOCK = new ReentrantReadWriteLock(); //SimpleAccountRealms are memory-only realms - no need for an additional cache mechanism since we're //already as memory-efficient as we can be: setCachingEnabled(false); }
SimpleAccountRealm内部有四个属性,Map<String, SimpleAccount> users:用于存放用户账号信息,Map<String, SimpleRole> roles用于存放角色名的信息。这两个都是各种配置的最终归属存储地。
ReadWriteLock USERS_LOCK:由于这些配置信息,一般不会去修改,大部分时间用于查询,所以要使用读写锁。一般的synchronized同步,不管你是读还是写,都要进行等待。写与写需要进行同步,写与读也要进行同步,但读与读却并不需要进行同步,所以对于那些经常读的场景,要使用读写锁ReadWriteLock 来提升性能。ReadWriteLock ROLES_LOCK同理。
有了以上数据源,实现父类的遗留的方法就比较简单了。如下:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; SimpleAccount account = getUser(upToken.getUsername()); if (account != null) { if (account.isLocked()) { throw new LockedAccountException("Account [" + account + "] is locked."); } if (account.isCredentialsExpired()) { String msg = "The credentials for account [" + account + "] are expired"; throw new ExpiredCredentialsException(msg); } } return account; } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = getUsername(principals); USERS_LOCK.readLock().lock(); try { return this.users.get(username); } finally { USERS_LOCK.readLock().unlock(); } }
代码就很简单了,就是从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等。
接口如下:
MutablePrincipalCollection如下:
public interface MutablePrincipalCollection extends PrincipalCollection { void add(Object principal, String realmName); void addAll(Collection principals, String realmName); void addAll(PrincipalCollection principals); void clear(); }
我们知道每一个标示都有所属的realm,所以再添加的时候,要带上realmName。
SimplePrincipalCollection:
private Map<String, Set> realmPrincipals;
一个重要的数据集合,key是realm的name,value是principal集合。
这个接口分支一直在强调,每个principal都是有所属的realm的。
PrincipalMap:我这一块没有搞明白,先放下。
AuthenticationInfo 它是含有用户和密码信息的地方:
public interface AuthenticationInfo extends Serializable { PrincipalCollection getPrincipals(); Object getCredentials(); }
AuthorizationInfo :存放用户权限的地方
public interface AuthorizationInfo extends Serializable { Collection<String> getRoles(); Collection<String> getStringPermissions(); Collection<Permission> getObjectPermissions(); }
类图如下:
MergableAuthenticationInfo 意味着AuthenticationInfo可以进行合并:
public interface MergableAuthenticationInfo extends AuthenticationInfo { void merge(AuthenticationInfo info); }
SaltedAuthenticationInfo 主要用于密码匹配,后续文章专门说明:
public interface SaltedAuthenticationInfo extends AuthenticationInfo { ByteSource getCredentialsSalt(); }
SimpleAuthenticationInfo:存储了三个重要的属性:
protected PrincipalCollection principals; protected Object credentials; protected ByteSource credentialsSalt;
然后就是实现了MergableAuthenticationInfo 接口,可以进行合并,这里的合并在第一篇文章中Realm认证中提到过:
public void merge(AuthenticationInfo info) { if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty()) { return; } if (this.principals == null) { this.principals = info.getPrincipals(); } else { if (!(this.principals instanceof MutablePrincipalCollection)) { this.principals = new SimplePrincipalCollection(this.principals); } ((MutablePrincipalCollection) this.principals).addAll(info.getPrincipals()); } //only mess with a salt value if we don't have one yet. It doesn't make sense //to merge salt values from different realms because a salt is used only within //the realm's credential matching process. But if the current instance's salt //is null, then it can't hurt to pull in a non-null value if one exists. // //since 1.1: if (this.credentialsSalt == null && info instanceof SaltedAuthenticationInfo) { this.credentialsSalt = ((SaltedAuthenticationInfo) info).getCredentialsSalt(); } Object thisCredentials = getCredentials(); Object otherCredentials = info.getCredentials(); if (otherCredentials == null) { return; } if (thisCredentials == null) { this.credentials = otherCredentials; return; } if (!(thisCredentials instanceof Collection)) { Set newSet = new HashSet(); newSet.add(thisCredentials); setCredentials(newSet); } // At this point, the credentials should be a collection Collection credentialCollection = (Collection) getCredentials(); if (otherCredentials instanceof Collection) { credentialCollection.addAll((Collection) otherCredentials); } else { credentialCollection.add(otherCredentials); } }
主要分principals、credentialsSalt 和credentials三项的合并,代码也和简单。
SimpleAuthorizationInfo:存放了认证用户的角色和用户权限。
protected Set<String> roles; protected Set<String> stringPermissions; protected Set<Permission> objectPermissions;
最重要的就是SimpleAccount:
public class SimpleAccount implements Account, MergableAuthenticationInfo, SaltedAuthenticationInfo, Serializable { private SimpleAuthenticationInfo authcInfo; private SimpleAuthorizationInfo authzInfo; private boolean locked; private boolean credentialsExpired; }
它有SimpleAuthenticationInfo 、SimpleAuthorizationInfo ,所以是用户认证信息和权限信息的汇总。
还有两个属性locked和credentialsExpired,用来表示用户的锁定和密码过期的状态。
至此整个SimpleAccount便介绍完了。
回到SimpleAccountRealm,SimpleAccountRealm已经拥有Map<String, SimpleAccount> users和Map<String, SimpleRole> roles数据了,但是这些数据是怎么产生的呢?这就需要交给它的子类TextConfigurationRealm来完成:
private volatile String userDefinitions; private volatile String roleDefinitions;
仅仅两个字符串包含了所有的用户和角色的配置总来源。所以TextConfigurationRealm主要就是对这两个字符串的解析:
@Override protected void onInit() { super.onInit(); processDefinitions(); } protected void processDefinitions() { try { //解析角色配置 processRoleDefinitions(); //解析用户配置 processUserDefinitions(); } catch (ParseException e) { String msg = "Unable to parse user and/or role definitions."; throw new ConfigurationException(msg, e); } } protected void processRoleDefinitions() throws ParseException { String roleDefinitions = getRoleDefinitions(); if (roleDefinitions == null) { return; } //先将角色字符串按行分割,然后每行再按照key value分割 Map<String, String> roleDefs = toMap(toLines(roleDefinitions)); processRoleDefinitions(roleDefs); } 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); } }
再通过PermissionResolver将字符串形式的权限转化成Permission对象,知道大致情况了,就可以了,不需要每一步都弄清楚。
TextConfigurationRealm主要用于解析两个配置字符串,这两个配置字符串的产生则继续交给子类来完成。IniRealm则是通过ini配置文件来产生这两个字符串,PropertiesRealm则是通过properties文件来产生这两个字符串。
至此,SimpleAccountRealm这一路就大致走通了,接下来就是另一条路JdbcRealm了。
public class JdbcRealm extends AuthorizingRealm { protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?"; protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?"; protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?"; protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?"; protected DataSource dataSource; }
首先是含有这几个默认的sql和DataSource dataSource,用于从数据库中获取相应的用户、角色、权限等数据。
根据上一篇文章我们知道JdbcRealm 要实现AuthenticatingRealm遗留的AuthenticationInfo doGetAuthenticationInfo和AuthorizingRealm遗留的AuthorizationInfo doGetAuthorizationInfo。下面就看看是怎么来实现的:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); // Null username is invalid if (username == null) { throw new AccountException("Null usernames are not allowed by this realm."); } Connection conn = null; SimpleAuthenticationInfo info = null; try { conn = dataSource.getConnection(); String password = null; String salt = null; switch (saltStyle) { case NO_SALT: //根据用户名去查找密码 password = getPasswordForUser(conn, username)[0]; break; case CRYPT: // TODO: separate password and hash from getPasswordForUser[0] throw new ConfigurationException("Not implemented yet"); //break; case COLUMN: String[] queryResults = getPasswordForUser(conn, username); password = queryResults[0]; salt = queryResults[1]; break; case EXTERNAL: password = getPasswordForUser(conn, username)[0]; //此时salt不存在数据库中,默认的值为username salt = getSaltForUser(username); } if (password == null) { throw new UnknownAccountException("No account found for user [" + username + "]"); } //根据用户名、密码、盐值构建一个SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName()); if (salt != null) { info.setCredentialsSalt(ByteSource.Util.bytes(salt)); } } catch (SQLException e) { final String message = "There was a SQL error while authenticating user [" + username + "]"; if (log.isErrorEnabled()) { log.error(message, e); } // Rethrow any SQL errors as an authentication exception throw new AuthenticationException(message, e); } finally { JdbcUtils.closeConnection(conn); } return info; } private String[] getPasswordForUser(Connection conn, String username) throws SQLException { String[] result; boolean returningSeparatedSalt = false; switch (saltStyle) { case NO_SALT: case CRYPT: case EXTERNAL: result = new String[1]; break; default: result = new String[2]; returningSeparatedSalt = true; } PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(authenticationQuery); ps.setString(1, username); // Execute query rs = ps.executeQuery(); // Loop over results - although we are only expecting one result, since usernames should be unique boolean foundResult = false; while (rs.next()) { // Check to ensure only one row is processed if (foundResult) { throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique."); } result[0] = rs.getString(1); if (returningSeparatedSalt) { result[1] = rs.getString(2); } foundResult = true; } } finally { JdbcUtils.closeResultSet(rs); JdbcUtils.closeStatement(ps); } return result; } protected String getSaltForUser(String username) { return username; }
代码很简单就不再一一细说。再看下doGetAuthorizationInfo是怎么实现的:
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //null usernames are invalid if (principals == null) { throw new AuthorizationException("PrincipalCollection method argument cannot be null."); } String username = (String) getAvailablePrincipal(principals); Connection conn = null; Set<String> roleNames = null; Set<String> permissions = null; try { conn = dataSource.getConnection(); // Retrieve roles and permissions from database roleNames = getRoleNamesForUser(conn, username); if (permissionsLookupEnabled) { permissions = getPermissions(conn, username, roleNames); } } catch (SQLException e) { final String message = "There was a SQL error while authorizing user [" + username + "]"; if (log.isErrorEnabled()) { log.error(message, e); } // Rethrow any SQL errors as an authorization exception throw new AuthorizationException(message, e); } finally { JdbcUtils.closeConnection(conn); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames); info.setStringPermissions(permissions); return info; }
第一步先根据PrincipalCollection 来获取用户名,第二步根据用户名来获取角色,第三部根据角色和用户名来获取权限。后两步都是执行简单的sql,不再说,看下如何由PrincipalCollection 获取用户名,该方法定义在CachingRealm中:
protected Object getAvailablePrincipal(PrincipalCollection principals) { Object primary = null; if (!CollectionUtils.isEmpty(principals)) { Collection thisPrincipals = principals.fromRealm(getName()); if (!CollectionUtils.isEmpty(thisPrincipals)) { primary = thisPrincipals.iterator().next(); } else { //no principals attributed to this particular realm. Fall back to the 'master' primary: primary = principals.getPrimaryPrincipal(); } } return primary; }
两种情况,首先是获取当前Realm的Principals,如果有取其第一个。如果没有,则调用getPrimaryPrincipal()方法。然后看下JdbcRealm的一个简单使用:
如果默认按照JdbcRealm的sql来作为数据库的查询来说,建表如下:
users表:
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(45) NOT NULL, `password` varchar(45) NOT NULL, `password_salt` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username_UNIQUE` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
user_roles表:
CREATE TABLE `user_roles` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(45) DEFAULT NULL, `role_name` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
roles_permissions表:
CREATE TABLE `roles_permissions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_name` varchar(45) DEFAULT NULL, `permission` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
文章最后会给出数据库sql文件。
然后就是配置ini文件:
[main] #realm dataSource=com.mchange.v2.c3p0.ComboPooledDataSource dataSource.driverClass=com.mysql.jdbc.Driver dataSource.jdbcUrl=jdbc:mysql://localhost:3306/shiro dataSource.user=root dataSource.password=XXXXXX jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm jdbcRealm.dataSource=$dataSource jdbcRealm.permissionsLookupEnabled=true securityManager.realms=$jdbcRealm
使用的dataSource是c3p0的dataSource,mysql驱动也是必然不能少的,所以maven中要加入依赖:
<!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.29</version> </dependency> <!-- 连接池 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency>
为了输出方便代码更改为:
public class ShiroTest { @Test public void testHelloworld() { init(); Subject subject=login("lg","123"); System.out.println(subject.hasRole("role1")); System.out.println(subject.hasRole("role2")); System.out.println(subject.hasRole("role3")); } private Subject login(String userName,String password){ //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(userName,password); subject.login(token); return subject; } private void init(){ //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //2、得到SecurityManager实例 并绑定给SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); } }
对于lg用户,在数据库中它是有两个角色的,role1和role2。所以结果为true、true、false。
true true false
OK,通过。最后附上JdbcRealm的使用例子。
作者:乒乓狂魔
发表评论
-
shiro源码分析(十一)SecurityManager
2015-01-16 05:59 0shiro源码分析(十一)SecurityManager -
shiro源码分析(九)RememberMe分析
2015-01-04 08:20 0shiro源码分析(八)RememberMe分析shiro源码 ... -
shiro源码分析(七)对称式加密解密
2015-01-01 10:29 0shiro源码分析(七)对称式加密解密shiro源码分析(七) ... -
shiro源码分析(八)ini配置文件的解析原理
2014-12-30 06:17 0shiro源码分析(七)ini配置文件的解析shiro源码分析 ... -
shiro源码分析(六)CredentialsMatcher 的案例分析
2015-01-04 07:39 7607有了上一篇文章的原理分析,这一篇文章主要结合原理来进行使用。 ... -
shiro源码分析(五)CredentialsMatcher
2014-12-29 07:39 11580Realm在验证用户身份的时候,要进行密码匹配。最简单的情况就 ... -
shiro源码分析(三)授权、认证、缓存的接口设计
2014-12-19 07:46 7119前两篇文章主要说的是认证过程,这一篇来分析下授权的过程。还是开 ... -
Subject Runas模块
2014-12-17 07:05 0Subject Runas模块Subject Runas模块S ... -
shiro源码分析(二)Subject和Session
2014-12-15 08:02 16674继续上一篇文章的案例 ... -
2 MapContext分析
2014-12-11 07:13 02 MapContext分析 -
1 AuthenticationInfo 是如何进行合并的?
2014-12-11 07:12 01 AuthenticationInfo 是如何进行合并的? -
shiro源码分析(一)入门
2014-12-11 07:21 13788最近闲来无事,准备读 ...
相关推荐
shiro自定义realm案例,参考文档:http://blog.csdn.net/qq_19558705/article/details/50775509
SpringMVC shiro源码 SpringMVC shiro源码 SpringMVC shiro源码
shiro入门及深入,对于想学习shiro的同学,是不错的学习资料。
shiro入门及深入,对于想学习shiro的同学,是不错的学习资料。
Spring Boot学习之Shiro源码【学习狂神说,自己手动书写,可以实现正常所需的功能】 Spring Boot学习之Shiro源码【学习狂神说,自己手动书写,可以实现正常所需的功能】 Spring Boot学习之Shiro源码【学习狂神说,...
shiro是一个非常好用的框架,shiro源码包,可以帮助shiro学习者更快更高效地学习,亲测好用。望采纳。解压后即可使用。
shiro 视频、源码及课件。 shiro 视频、源码及课件。 shiro 视频、源码及课件。
整合SSM框架的shiro源代码,可供学习使用,里面有详细的注解和配置,
Apache Shiro 是目前使用率较高的一个 Java 安全框架。本视频基于 Shiro 的新版本 ...2.Shiro 集成 Web 具体使用 3.Shiro 标签使用 4.Shiro 会话机 5.自定义 Realm 第五章 加密 1.shiro 加密解密 2.shiro 加密应用
主要是SSH整合Shiro框架中的密码加密、认证、授权。主要是SSH整合Shiro框架中的密码加密、认证、授权。
这个可是能编辑通过的,偶试了 jdk6下,make成功
这里是shiro在web应用中自定义Realm的代码,以便做一个参考
shiro源码(shiro-root-1.8.0-source-release.zip)
Apache_Shiro_使用手册(四)Realm_实现
jsp+数据库+shiro 源码及文档
NULL 博文链接:https://lgbolgger.iteye.com/blog/2170522
跟我学Shiro源码
shiro源码(shiro-root-1.10.0-source-release.zip)
Shiro基本使用详解以及多Realm使用和配置,拿来可以直接使用,也可以在此基础上进行自己业务逻辑的添加和修改,如果希望进一步深入学习,可以查看我的博客,可以查看...或给我留言