当前位置:   article > 正文

Shiro基本使用

shiro

Shiro基本使用

1、什么是Shiro

Shiro是Apache的java安全框架。Apache Shiro是一个功能强大、灵活的开源安全框架,可以清晰地处理身份验证、授权、企业会话管理和加密。

官网地址:http://shiro.apache.org/

2、基础功能

以下是shiro的产品特性:

shiro框架结构

  • Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份
  • Authorization:授权,验证已认证的用户有哪些角色和资源访问权限
  • Session Management:会话管理,管理特定于用户的会话,即使是非web或JavaSE 环境
  • Cryptography:密码/加密,使用密码算法保持数据安全,同时仍易于使用

以上四个部分组成shiro主要的安全保障。还有其他的支持辅组主要功能:

Web Support:Web 支持,可以非常容易的集成到 Web 环境

Caching:缓存,用户登陆信息、拥有的角色信息、权限,减少查询次数,提高效率。

Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限

​ 自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了

3、体系结构(工作流程)

image-20201229155033817

  • Subject:主体,即当前和应用程序交互的对象。
  • SecurityManager:安全管理器,所有的Subject都交给委托给它。
  • Realms:域,是Shiro和应用数据的连接点,提供认证用户和授权的API,由开发人员维护。

4、源码分析

源码地址:https://github.com/apache/shiro

4.1、Authentication认证流程

参考源码提供的quickstart创建maven工程。

image-20201230112728132

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

先看一下配置类,首先是简单的日志打印级别和输出格式的设置

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

然后是主要的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

  • 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

看到有[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();
        }
    }
}
  • 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

用户认证的步骤:

  • 读取我们resources下面的shiro.ini 创建SecurityManager工厂
  • 将获取的 SecurityManager 并绑定到 SecurityUtils
  • 通过 SecurityUtils 得到 Subject, 然后获取身份验证的 Token,如用户名 / 密码;
  • 调用 subject.login 方法进行登录,其会自动委托给 SecurityManager.login 方法进行登录;
  • 身份验证失败请捕获 AuthenticationException或其子类,常见的如:UnknownAccountException(账号错误)、IncorrectCredentialsException (凭证(密码)错误)

流程图:

image-20201230142617172

subject.login最终执行到 SimpleAccountRealm类的doGetAuthenticationInfo(AuthenticationToken token)方法

public class SimpleAccountRealm extends AuthorizingRealm {

}
  • 1
  • 2
  • 3

image-20201230143013970

SimpleAccountRealm类继承了AuthorizingRealm类,AuthorizingRealm继承了AuthenticatingRealm类。这个类里面就有抽象方法

protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
  • 1

执行一下程序,抛出异常,因为我们这边的用户名和密码不符合shiro.ini里的配置。我们再尝试

UsernamePasswordToken token = new UsernamePasswordToken("root", "secret");
  • 1

执行程序:

image-20201230145459628

4.2、Authorization授权流程

登陆认证通过的用户有相应的角色,赋予对应的资源访问权限。

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • subject.hasRole():判断认证用户是否有某个权限
  • subject.isPermitted():判断用户是否有某个权限

执行程序

image-20201230152219039

最终还是进入到了SimpleAccountRealm这个类里面的doGetAuthorizationInfo()方法,这个方法继承自AuthorizingRealm

protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1);
  • 1

5、总结

创建subject托管到SecurityManager最终在realms里面进行数据安全的检验和授权。doGetAuthenticationInfo(AuthenticationToken token)doGetAuthorizationInfo(PrincipalCollection var1)两个方法中进行逻辑处理。shiro的例子是在resoueces里配置.ini文件,实际的项目里一般根据RBAC模型设计用户、角色、资源和权限数据库。

参考:

官网地址:http://shiro.apache.org/

相关:
Spring Security 基本使用

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号