Shiro 框架基本使用

简介: Apache Shiro是一个强大且易用的Java安全框架,它执行身份验证、授权、密码和会话管理。Shiro框架通过其三个核心组件:Subject、SecurityManager和Realms,提供了一个通用的安全认证框架。

@[TOC]

Shiro框架介绍

Apache Shiro是一个强大且易用的Java安全框架,它执行身份验证、授权、密码和会话管理。Shiro框架通过其三个核心组件:Subject、SecurityManager和Realms,提供了一个通用的安全认证框架。

Shiro官方:http://shiro.apache.org

Shiro的核心架构图

image.png

Shiro 基本使用

认证流程:

image.png

授权流程:

image.png

SimpleAccountRealm

认证代码:

@Test
public void authen() {
   
   
    //认证的发起者(subject),   SecurityManager,   Realm
    //1. 准备Realm(基于内存存储用户信息)
    SimpleAccountRealm realm = new SimpleAccountRealm();
    realm.addAccount("admin", "admin", "超级管理员", "商家");

    //2. 准备SecurityManager
    DefaultSecurityManager securityManager = new DefaultSecurityManager();

    //3. SecurityManager和Realm建立连接
    securityManager.setRealm(realm);

    //4. subject和SecurityManager建立联系
    SecurityUtils.setSecurityManager(securityManager);

    //5. 声明subject
    Subject subject = SecurityUtils.getSubject();

    //6. 发起认证
    subject.login(new UsernamePasswordToken("admin", "admin"));
    // 如果认证时,用户名错误,抛出:org.apache.shiro.authc.UnknownAccountException异常
    // 如果认证时,密码错误,抛出:org.apache.shiro.authc.IncorrectCredentialsException:

    //7. 判断是否认证成功
    System.out.println(subject.isAuthenticated());

    //8. 退出登录后再判断
    //        subject.logout();
    //        System.out.println("logout方法执行后,认证的状态:" + subject.isAuthenticated());

    //9. 授权是在认证成功之后的操作!!!
    // SimpleAccountRealm只支持角色的授权
    System.out.println("是否拥有超级管理员角色:" + subject.hasRole("超级管理员"));
    subject.checkRole("商家");
    // check方法校验角色时,如果没有指定角色,会抛出异常:org.apache.shiro.authz.UnauthorizedException: Subject does not have role [角色信息]
}

IniRealm

基于文件存储用户名、密码、角色等信息

准备一个.ini文件,存储用户信息,并且IniRealm支持权限校验

[users]
username=password,role1,role2
admin=admin,超级管理员,运营
[roles]
role1=perm1,perm2
超级管理员=user:add,user:update,user:delete

代码:

@Test
public void authen(){
   
   
    //1. 构建IniRealm
    IniRealm realm = new IniRealm("classpath:shiro.ini");

    //2. 构建SecurityManager绑定Realm
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);

    //3. 基于SecurityUtils绑定SecurityManager并声明subject
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();

    //4. 认证操作
    subject.login(new UsernamePasswordToken("admin","admin"));

    //5. 角色校验
    // 超级管理员
    System.out.println(subject.hasRole("超级管理员"));
    subject.checkRole("运营");

    //6. 权限校验
    System.out.println(subject.isPermitted("user:update"));
    // 如果没有响应的权限,就抛出异常:UnauthorizedException: Subject does not have permission [user:select]
    subject.checkPermission("user:delete");
}

JdbcRealm

基于数据库存储用户名、密码、角色等信息。

用户认证、授权时推荐的表结构设计,经典五张表!

image.png

代码:

@Test
public void authen(){
   
   
    //1. 构建IniRealm
    JdbcRealm realm = new JdbcRealm();

    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql:///shiro");
    dataSource.setUsername("root");
    dataSource.setPassword("root");
    realm.setDataSource(dataSource);

    realm.setPermissionsLookupEnabled(true);

    //2. 构建SecurityManager绑定Realm
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);

    //3. 基于SecurityUtils绑定SecurityManager并声明subject
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();

    //4. 认证操作
    subject.login(new UsernamePasswordToken("admin","admin"));

    //5. 授权操作(角色)
    System.out.println(subject.hasRole("超级管1理员"));

    //6. 授权操作(权限)
    System.out.println(subject.isPermitted("user:add"));

}

SQL构建代码

DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `permission` varchar(128) NOT NULL,
  `role_name` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES ('1', 'user:add', '超级管理员');
INSERT INTO `roles_permissions` VALUES ('2', 'user:update', '超级管理员');
INSERT INTO `roles_permissions` VALUES ('3', 'user:select', '运营');

-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'admin', 'admin');

-- ----------------------------
-- Table structure for `user_roles`
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(128) NOT NULL,
  `username` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES ('1', '超级管理员', 'admin');
INSERT INTO `user_roles` VALUES ('2', '运营', 'admin');

CustomRealm(自定义Realm)

仿照JdbcRealm实现一个自定义的Realm对象

  • 声明POJO类,继承AuthorizingRealm
        public class CustomRealm extends AuthorizingRealm {
         
         
            ……………………
        }
    
  • 重写doGetAuthenticationInfo方法(认证)

        /**
         * 认证方法,只需要完成用户名校验即可,密码校验由Shiro内部完成
         * @param token  用户传入的用户名和密码
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
         
         
            //1. 基于Token获取用户名
            String username = (String) token.getPrincipal();
    
            //2. 判断用户名(非空)
            if(StringUtils.isEmpty(username)){
         
         
                // 返回null,会默认抛出一个异常,org.apache.shiro.authc.UnknownAccountException
                return null;
            }
    
            //3. 如果用户名不为null,基于用户名查询用户信息
            User user = this.findUserByUsername(username);
    
            //4. 判断user对象是否为null
            if(user == null){
         
         
                return null;
            }
    
            //5. 声明AuthenticationInfo对象,并填充用户信息
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"CustomRealm!!");
    
            //6. 返回info
            return info;
        }
    
        // 模拟数据库操作
        private User findUserByUsername(String username) {
         
         
            if("admin".equals(username)){
         
         
                User user = new User();
                user.setId(1);
                user.setUsername("admin");
                user.setPassword("admin");
                return user;
            }
            return null;
        }
    
  • 重写doGetAuthenticationInfo方法(密码加密加盐)
    ```java
    {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(1024);
        this.setCredentialsMatcher(matcher);
    }
    
  /**
   * 认证方法,只需要完成用户名校验即可,密码校验由Shiro内部完成
   * @param token  用户传入的用户名和密码
   * @return
   * @throws AuthenticationException
   */
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
      //1. 基于Token获取用户名
      String username = (String) token.getPrincipal();

      //2. 判断用户名(非空)
      if(StringUtils.isEmpty(username)){
          // 返回null,会默认抛出一个异常,org.apache.shiro.authc.UnknownAccountException
          return null;
      }

      //3. 如果用户名不为null,基于用户名查询用户信息
      User user = this.findUserByUsername(username);

      //4. 判断user对象是否为null
      if(user == null){
          return null;
      }

      //5. 声明AuthenticationInfo对象,并填充用户信息
      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"CustomRealm!!");
      // 设置盐!
      info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
      //6. 返回info
      return info;
  }


  // 模拟数据库操作
  private User findUserByUsername(String username) {
      if("admin".equals(username)){
          User user = new User();
          user.setId(1);
          user.setUsername("admin");
          user.setPassword("1ebc4dcaf1e21b814ece65f27531f1a9");
          user.setSalt("weruiothergjkdfnbgjkdfngjkdf");
          return user;
      }
      return null;
  }
```
  • 重写doGetAuthorizationInfo方法(授权)

    // 授权方法,授权是在认证之后的操作
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
         
         
        //1. 获取认证用户的信息
        User user = (User) principals.getPrimaryPrincipal();
    
        //2. 基于用户信息获取当前用户拥有的角色。
        Set<String> roleSet = this.findRolesByUser();
    
        //3. 基于用户拥有的角色查询权限信息
        Set<String> permSet = this.findPermsByRoleSet(roleSet);
    
        //4. 声明AuthorizationInfo对象作为返回值,传入角色信息和权限信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roleSet);
        info.setStringPermissions(permSet);
    
        //5. 返回
        return info;
    }
    
    private Set<String> findPermsByRoleSet(Set<String> roleSet) {
         
         
        Set<String> set = new HashSet<>();
        set.add("user:add");
        set.add("user:update");
        return set;
    }
    
    private Set<String> findRolesByUser() {
         
         
        Set<String> set = new HashSet<>();
        set.add("超级管理员");
        set.add("运营");
        return set;
    }
    
相关文章
|
1月前
|
安全 Java 数据库
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
这篇文章是关于Apache Shiro权限管理框架的详细学习指南,涵盖了Shiro的基本概念、认证与授权流程,并通过Spring Boot测试模块演示了Shiro在单应用环境下的使用,包括与IniRealm、JdbcRealm的集成以及自定义Realm的实现。
42 3
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
288 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
缓存 算法 安全
快速学会如何使用Shiro
快速学会如何使用Shiro
121 2
|
Java API Maven
【Shiro】基本使用
1、环境准备 1、Shiro不依赖容器,直接创建maven工程即可 2、添加依赖
80 0
|
安全 数据安全/隐私保护
【Shiro】第三章 Shiro入门(一)
【Shiro】第三章 Shiro入门
77 1
|
存储 算法 程序员
【Shiro】第三章 Shiro入门(二)
【Shiro】第三章 Shiro入门(二)
81 1
|
存储 算法 数据安全/隐私保护
【Shiro】第三章 Shiro入门(三)
【Shiro】第三章 Shiro入门(三)
79 1
|
缓存 数据库 数据安全/隐私保护
【Shiro】第三章 Shiro入门(四)
【Shiro】第三章 Shiro入门(四)
82 0
|
Java 数据库 数据安全/隐私保护
Shiro学习之Shiro基本使用(2)
Shiro学习之Shiro基本使用(2)
57 0
|
Java API 数据库
Shiro学习之Shiro基本使用(1)
Shiro学习之Shiro基本使用(1)
89 0