赞
踩
Shiro是Apache的java安全框架。Apache Shiro是一个功能强大、灵活的开源安全框架,可以清晰地处理身份验证、授权、企业会话管理和加密。
以下是shiro的产品特性:
以上四个部分组成shiro主要的安全保障。还有其他的支持辅组主要功能:
Web Support:Web 支持,可以非常容易的集成到 Web 环境
Caching:缓存,用户登陆信息、拥有的角色信息、权限,减少查询次数,提高效率。
Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限
自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
源码地址:https://github.com/apache/shiro
参考源码提供的quickstart创建maven工程。
pom.xml引入依赖
<dependencies> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.0</version> </dependency> <!-- 日志logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> </dependencies>
先看一下配置类,首先是简单的日志打印级别和输出格式的设置
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries log4j.logger.org.apache=WARN # Spring log4j.logger.org.springframework=WARN # Default Shiro logging log4j.logger.org.apache.shiro=INFO # Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
然后是主要的shiro.ini配置
[users] # user 'root' with password 'secret' and the 'admin' role root = secret, admin # user 'guest' with the password 'guest' and the 'guest' role guest = guest, guest # user 'presidentskroob' with password '12345' ("That's the same combination on # my luggage!!!" ;)), and role 'president' presidentskroob = 12345, president # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz' darkhelmet = ludicrousspeed, darklord, schwartz # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz' lonestarr = vespa, goodguy, schwartz # ----------------------------------------------------------------------------- # Roles with assigned permissions # # Each line conforms to the format defined in the # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc # ----------------------------------------------------------------------------- [roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5
看到有[user]和[roles]两个配置。[user]配置的是用户的账号对应的密码和角色,如root用户的密码是secret,角色是admin。而[roles]则对应的是角色的权限,admin拥有所有权限。
接下来新建一个TestShiro.java类
public class TestShiro { // 日志打印 private static final Logger log = LoggerFactory.getLogger(TestShiro.class); public static void main(String[] args) { // 1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); // 2、获取securityManager实例,设置全局securityManager SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); // 3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); // 4、进行登陆认证 UsernamePasswordToken token = new UsernamePasswordToken("username", "123456"); try { subject.login(token); log.info("认证成功!"); } catch (AuthenticationException e) { //5、异常处理 log.error(e.getMessage()); } // 用户已经登录 if (subject.isAuthenticated()) { // 6、退出 subject.logout(); } } }
用户认证的步骤:
resources
下面的shiro.ini
创建SecurityManager
工厂SecurityManager
并绑定到 SecurityUtils
SecurityUtils
得到 Subject
, 然后获取身份验证的 Token
,如用户名 / 密码;subject.login
方法进行登录,其会自动委托给 SecurityManager.login
方法进行登录;AuthenticationException
或其子类,常见的如:UnknownAccountException
(账号错误)、IncorrectCredentialsException
(凭证(密码)错误)流程图:
subject.login
最终执行到 SimpleAccountRealm类的doGetAuthenticationInfo(AuthenticationToken token)方法
public class SimpleAccountRealm extends AuthorizingRealm {
}
而SimpleAccountRealm
类继承了AuthorizingRealm
类,AuthorizingRealm
继承了AuthenticatingRealm
类。这个类里面就有抽象方法
protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
执行一下程序,抛出异常,因为我们这边的用户名和密码不符合shiro.ini
里的配置。我们再尝试
UsernamePasswordToken token = new UsernamePasswordToken("root", "secret");
执行程序:
登陆认证通过的用户有相应的角色,赋予对应的资源访问权限。
UsernamePasswordToken token = new UsernamePasswordToken("root", "secret");
try {
subject.login(token);
log.info("认证成功!");
} catch (AuthenticationException e) {
log.error(e.getMessage());
}
boolean flag = subject.hasRole("schwartz");
System.out.println(flag);
subject.hasRole()
:判断认证用户是否有某个权限subject.isPermitted()
:判断用户是否有某个权限执行程序
最终还是进入到了SimpleAccountRealm
这个类里面的doGetAuthorizationInfo()
方法,这个方法继承自AuthorizingRealm
类
protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1);
创建subject托管到SecurityManager最终在realms里面进行数据安全的检验和授权。doGetAuthenticationInfo(AuthenticationToken token)
和doGetAuthorizationInfo(PrincipalCollection var1)
两个方法中进行逻辑处理。shiro的例子是在resoueces里配置.ini文件,实际的项目里一般根据RBAC模型设计用户、角色、资源和权限数据库。
参考:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。