Shiro 框架详解

Shiro 是一款轻量级的 Java 安全框架,提供了身份认证、授权、加密和会话管理等功能。它可以集成到任何 Java Web 应用程序中,并且易于使用和扩展。Shiro 的设计理念是简洁而灵活,不仅可以应用于 Web 应用程序,还可以应用于命令行、移动设备和分布式系统等各种应用场景。

1. Shiro 的概述

Shiro 是一个开源的 Java 安全框架,由 Apache 开发和维护。Shiro 可以帮助开发人员快速实现安全特性,包括身份认证、授权、加密和会话管理等。Shiro 的目标是简化 Java 安全编程,并提供更好的开发体验。

Shiro 的主要特点如下:

  • 易于学习和使用:Shiro 设计简单,易于学习和使用。
  • 灵活性高:Shiro 可以适用于任何应用场景,支持多种应用程序类型。
  • 安全性高:Shiro 的安全性能比较优越,提供了多种方式来保护应用程序的安全性。
  • 扩展性好:Shiro 框架提供了可扩展性插件机制,可以方便地扩展框架的功能,满足不同的需求。
  • 企业级支持:Shiro 是从 Apache 基金会获得支持的框架,拥有众多企业用户。

2. Shiro 的基本组件

Shiro 的基本组件包括 Subject、SecurityManager 和 Realms 等。下面我们分别介绍一下这些组件的作用和作用。

Subject

Subject 代表当前用户,是 Shiro 框架中最重要的组件之一。Subject 封装了用户的所有信息,包括身份(用户名和密码)和角色等。在一个应用程序中,可能有多个 Subject,每个 Subject 可以访问应用程序中的资源。

用户可以通过 Subject 登录应用程序,并执行诸如访问资源、修改个人配置等操作。Shiro 提供了简单易用的方法来管理用户的登录和退出行为,以及 Session 管理等。

SecurityManager

SecurityManager 是 Shiro 的核心组件,负责管理和协调整个应用程序的安全机制。它的主要职责是认证、授权、加密和会话管理等。

SecurityManager 将应用程序中的所有安全操作委托给适当的 Realms 进行处理,并存储和管理有关用户身份、角色和权限等信息。SecurityManager 还可以配置多个 Realms,以便应用程序可以集成不同的认证和授权方案。

Realm

Realm 是 SecurityManager 中负责处理用户身份认证和授权的组件。Shiro 支持多种不同类型的 Realm,包括 JDBC Realm、LDAP Realm、Active Directory Realm 等。

每个 Realm 负责验证用户的身份,并获取用户的权限信息,以便 SecurityManager 可以根据这些信息进行访问控制和授权。Realm 还可以实现缓存机制,提高系统性能。

3. Shiro 的权限控制

Shiro 提供了灵活的权限控制机制,可以对应用程序中的资源进行细粒度的访问控制。Shiro 的权限控制基于角色和权限的概念,其中:

  • 角色是用户的一组角色,可以表示用户在系统中的不同身份;
  • 权限是用户针对某个资源或操作所具有的权限。

Shiro 的权限控制机制包括以下几个步骤:

  1. 用户登录系统,通过 Subject 实例获取当前用户信息;
  2. 当用户进行某个操作时,Shiro 会根据用户请求的资源和操作类型,检查该用户是否具有执行该操作的权限。
  3. 如果用户具备该权限,则允许用户进行操作;否则,Shiro 会拒绝用户的请求,并返回相应的错误信息。

Shiro 支持多种方式来授权,包括基于角色和基于权限。角色授权是将用户分配到不同的角色,每个角色具有特定的权限,从而实现对用户的授权。权限授权是直接为用户授权某个资源或操作,从而实现对用户的授权。

4. Shiro 的会话管理

会话管理是 Web 应用程序中一个非常重要的安全特性。Shiro 提供了丰富的会话管理功能,包括 Cookie 管理、Session 管理和集群会话管理等。

Shiro 的会话管理机制包括以下几个步骤:

  1. 当用户登录系统时,Shiro 会自动创建一个 Session 对象,并将其关联到用户身份信息上,以便在整个应用程序生命周期内管理用户的会话状态。
  2. 用户进行某个操作时,Shiro 会检查该用户是否具有执行该操作的权限,并根据情况更新 Session 中的状态信息。
  3. 当用户退出系统时,Shiro 会清除用户的 Session 数据,并删除相关的 Session 记录。

Shiro 还支持集群会话管理,可以通过配置将会话信息存储在数据库、Redis 或其他数据源中,以便在分布式应用程序中进行会话管理。

5. Shiro 的加密与解密

Shiro 支持多种加密和解密算法,包括 MD5、SHA、AES 等。Shiro 不仅提供了简单易用的加密和解密 API,还提供了安全的密码管理和哈希函数实现。

在 Shiro 中,需要对密码进行加密和解密时,可以使用 Shiro 内置的加密和解密工具类。例如,我们可以使用 CredentialsMatcher 进行密码验证,或者使用 SimpleHash 类进行密码加密。

Shiro 的密码加密和解密功能的主要目的是保护用户的个人信息和隐私,防止其被黑客攻击和非法访问,从而提高系统的安全性。

6. Shiro 的集成开发

Shiro 可以与各种 Web 框架和数据源集成,以满足不同应用场景的需求。Shiro 的集成开发可以分为以下三个步骤:

  1. 配置 SecurityManager:首先,需要在应用程序的配置文件中配置 SecurityManager,以便为应用程序提供统一的身份验证和授权管理。
  2. 配置 Realm:其次,需要根据实际需要配置 Realm,以便根据数据库、LDAP 或其他数据源来验证用户身份,并获取用户权限信息。
  3. 配置 FilterChain:最后,需要配置 FilterChain,以便拦截访问请求,并根据用户的角色和权限等信息来判断是否允许用户进行访问。

在集成开发时,需要使用 Shiro 提供的相应 API 和插件来集成 Shiro 到应用程序中。具体来说,可以根据不同的框架和数据源选择不同的 Shiro 插件。例如,对于 Spring 应用程序,可以使用 Shiro-Spring 插件;对于数据源,可以使用 Shiro-JDBC 插件或 Shiro-LDAP 插件等。

7. Shiro 配置案例实战演练

首先,在 pom.xml 文件中添加依赖项:

<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- MyBatis + Spring Boot -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>

    <!-- Shiro -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.7.1</version>
    </dependency>

    <!-- Spring Shiro Integration -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.7.1</version>
    </dependency>

    <!-- H2 Database -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>

    <!-- Test -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

在上述依赖项中,我们引入了 Spring Boot、MyBatis 和 Shiro 的相关依赖项。

然后,我们实现一个 UserMapper 接口来操作用户数据:

@Mapper
public interface UserMapper {
    User selectByUsername(String username);
    Set<String> selectRolesByUsername(String username);
    Set<String> selectPermissionsByUsername(String username);
}

在该接口中,我们声明了 selectByUsername、selectRolesByUsername 和 selectPermissionsByUsername 三个方法,用于查询指定用户名的用户、角色和权限信息。

接下来,我们实现一个 User 实体类:

public class User implements Serializable {
    private Long id;
    private String username;
    private String password;
    private Boolean enabled;
    private Set<Role> roles;
    // getters and setters
}

在该类中,我们定义了 id、username、password、enabled 和 roles 属性。roles 属性为一个 Set 集合,存储用户所拥有的角色信息。

然后,我们实现一个 Role 实体类:

public class Role implements Serializable {
    private Long id;
    private String name;
    private String description;
    private Set<Permission> permissions;
    // getters and setters
}

在该类中,我们定义了 id、name、description 和 permissions 属性。permissions 属性为一个 Set 集合,存储角色所拥有的权限信息。

最后,我们实现一个 Permission 实体类:

public class Permission implements Serializable {
    private Long id;
    private String name;
    private String description;
    // getters and setters
}

在该类中,我们定义了 id、name 和 description 属性,用于存储权限信息。

接下来,我们需要实现 ShiroConfig 类来完成 Shiro 配置:

@Configuration
public class ShiroConfig {

    @Bean
    public DefaultWebSecurityManager securityManager(Realm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }

    @Bean
    public Realm realm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }

    @Bean
    public CredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
        credentialsMatcher.setStoredCredentialsHexEncoded(false);
        return credentialsMatcher;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/admin/**", "authc, roles[admin]");
        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
        shiroFilter.setLoginUrl("/login");
        shiroFilter.setSuccessUrl("/");
        shiroFilter.setUnauthorizedUrl("/unauthorized");
        return shiroFilter;
    }
}

在该类中,我们通过 @Bean 注解定义了 Shiro 的安全管理器、Realm、CredentialsMatcher 和过滤器链等相关配置。其中,我们使用 MyShiroRealm 来连接数据库,并设置了密码加密算法为 SHA-256。

然后,我们可以定义一个 UserController 类来处理用户相关的请求和操作:

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            return "login success";
        } catch (AuthenticationException e) {
            return "login failed";
        }
    }

    @GetMapping("/admin/users")
    @RequiresRoles("admin")
    public List<User> getUsers() {
        return userService.getAllUsers();
    }
}

在该类中,我们定义了 login 方法用于进行身份认证操作,接受用户名和密码参数,并调用 Shiro 提供的 Subject 对象对用户进行身份认证。如果身份认证成功,则返回字符串 “login success”,否则返回 “login failed”。

另外,getUsers 方法用于获取所有用户列表,在访问该 URL 时,需要用户具有 admin 角色权限才能访问。我们可以使用 @RequiresRoles 注解来对该方法进行授权管理。

最后,我们实现一个 UserService 类来操作用户数据:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User getByUsername(String username) {
        return userMapper.selectByUsername(username);
    }

    @Override
    public Set<String> getRolesByUsername(String username) {
        return userMapper.selectRolesByUsername(username);
    }

    @Override
    public Set<String> getPermissionsByUsername(String username) {
        return userMapper.selectPermissionsByUsername(username);
    }

    @Override
    public List<User> getAllUsers() {
        return userMapper.selectAllUsers();
    }
}

在该类中,我们使用 UserMapper 接口来访问数据库,实现了根据用户名获取用户、获取用户角色和权限以及获取所有用户列表的方法。

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大家都说我身材好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值