- 浏览: 236509 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
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 7731有了上一篇文章的原理分析,这一篇文章主要结合原理来进行使用。 ... -
shiro源码分析(五)CredentialsMatcher
2014-12-29 07:39 11698Realm在验证用户身份的时候,要进行密码匹配。最简单的情况就 ... -
shiro源码分析(三)授权、认证、缓存的接口设计
2014-12-19 07:46 7195前两篇文章主要说的是认证过程,这一篇来分析下授权的过程。还是开 ... -
Subject Runas模块
2014-12-17 07:05 0Subject Runas模块Subject Runas模块S ... -
shiro源码分析(二)Subject和Session
2014-12-15 08:02 16788继续上一篇文章的案例 ... -
2 MapContext分析
2014-12-11 07:13 02 MapContext分析 -
1 AuthenticationInfo 是如何进行合并的?
2014-12-11 07:12 01 AuthenticationInfo 是如何进行合并的? -
shiro源码分析(一)入门
2014-12-11 07:21 13897最近闲来无事,准备读 ...
相关推荐
- **源码分析**:通过阅读Shiro的源码,可以理解其内部的工作机制,包括如何进行身份验证、授权以及会话管理,有助于定制化开发和性能优化。 - **设计模式**:Shiro的源码中大量运用了设计模式,如工厂模式、代理...
在"Shiro源码分析(六)CredentialsMatcher 的案例分析"这篇博文中,作者深入剖析了Shiro中用于验证用户凭证的`CredentialsMatcher`组件。下面我们将详细探讨这一核心机制及其相关知识点。 1. **CredentialsMatcher...
Apache Shiro 是目前使用率较高的一个 Java 安全框架。本视频基于 Shiro 的新版本 ...2.Shiro 集成 Web 具体使用 3.Shiro 标签使用 4.Shiro 会话机 5.自定义 Realm 第五章 加密 1.shiro 加密解密 2.shiro 加密应用
2. **案例分析**:通过具体的场景,演示如何使用Shiro实现登录、权限控制等功能。 3. **最佳实践**:提供在实际项目中使用Shiro时的一些最佳实践和注意事项,帮助避免常见问题。 4. **实战教程**:可能包含一系列...
通过对 Shiro1.2.2 的源码分析,我们可以了解到它如何处理各种安全问题,以及如何构建高效、灵活的安全架构。同时,源码的学习有助于我们理解和解决在实际开发中遇到的安全问题,提升我们的编程技能。
"跟我学Shiro源码"这个主题旨在深入理解Shiro的工作原理,通过分析源码来提升我们对安全编程的认知。 1. **Shiro架构** Shiro 的核心组件包括 Realm(认证与授权信息源)、SecurityManager(安全管理器)、Subject...
通过分析这个源码,你可以理解如何在SpringBoot项目中构建一套完整的权限管理系统,包括用户的登录、权限校验以及对不同资源的访问控制。这不仅可以应用于简单的入门项目,也可以作为实际项目的基础框架,根据需求...
通过阅读文档和分析源码,我们可以了解Shiro如何与JSP和数据库协作,如何实现用户认证、授权,以及如何定制Shiro以适应特定项目需求。对于Java Web开发者来说,掌握这些知识能提升应用的安全性和用户体验。
4. 源码分析 在`client1`目录下,你可能会看到如下关键文件: - `CasShiroFilter`: 自定义的过滤器,结合了CAS和Shiro的功能,对请求进行拦截和处理。 - `CustomCasRealm`: 自定义的 Realm 类,实现Shiro的认证和...
在《跟我学Shiro》这本书中,作者深入浅出地讲解了 Shiro 的核心概念与实际应用场景,配合源码分析,有助于读者更好地理解和掌握 Shiro 的工作原理。 1. **Shiro 概述** - Shiro 的设计目标是简化应用安全开发,它...
尚硅谷_Shiro_源码、课件 · 01.尚硅谷_Shiro_简介 · 02.尚硅谷_Shiro_HelloWorld · 03.尚硅谷_Shiro_集成 Spring · 04.尚硅谷_Shiro_工作流程(1) · 05.尚硅谷_Shiro_DelegatingFilterProxy · 06. 尚硅谷...
- **Authorization**: 分析`org.apache.shiro.authz`包,了解权限和角色的处理逻辑。 - **Session Management**: 研究`org.apache.shiro.session`和`org.apache.shiro.session.mgt`包,理解Shiro如何管理和存储会话...
5. **源码分析** 提供的"springboot-shiro"源码可能包含了以上所有步骤的实现,包括配置文件、自定义Realm、过滤器链定义、Controller层的权限注解等。通过分析这些源码,我们可以深入理解SpringBoot与Shiro的整合...
通过分析源码,你可以了解到如何在实际项目中配置和使用Shiro,例如设置安全配置、编写自定义 Realm 或 Filter,以及处理会话过期等问题。 总之,“shiro-root-1.2.3-source-release”源码不仅展示了Shiro的架构和...
尚硅谷Shiro源码提供了对这个框架深入理解的窗口,让我们有机会研究其内部机制。 1. **身份认证**:Shiro提供了一种灵活的认证机制,可以处理用户名/密码、数字证书等多种认证方式。它通过Subject接口与真实用户...
通过阅读`shiro源码分析(pdf+word)`,你可以深入探究Shiro的内部机制,如`RememberMe`服务、会话管理器的工作流程,以及加密算法的应用等。 总的来说,Apache Shiro是一个全面且易用的Java安全框架,适合各种规模...
8. **源码分析**:提供的abel_shiro压缩包中的源码可以作为学习和参考的实例,通过阅读源码,理解Shiro如何与Spring MVC协同工作,如何处理登录、注销以及权限验证的具体流程。 总之,Spring MVC和Shiro的整合使...
Apache Shiro 是一个强大且易用的...通过分析Shiro源码,我们可以了解其内部机制,更好地定制和扩展Shiro以满足项目的特定需求。同时,结合Spring框架的整合,可以使Shiro的功能更加强大,提高应用的安全性和可维护性。
Apache Shiro 是一个强大且易用的Java安全框架,提供...通过阅读和分析源码,你可以深入理解Shiro的核心组件和工作流程,为自己的项目构建安全框架打下坚实的基础。记得在实践中不断探索和调整,以适应不同的安全需求。