shiro框架学习笔记

最近学习了 权限框架shiro的知识,做一下 学习的笔记

使用ini

这是shiro 最简单的用法,首先创建一个demo.ini文件,里面写入如下的内容

[users]
xiezihao=123456,admin
[roles]
admin = user.insert,user.update

下面对上面的配置进行一下解释
[users] 代表的是用户,之后在代码中做登录的时候使用,比如这里的配置中,的一是就是 ,用户名是xiezihao,密码是123456,拥有一个admin的角色。
[roles] 代表的是角色的意思,一个用户可以对应有多个角色,这里的一是是,admin这个角色拥有,user.insert 和 user.update 两种操作的权限

下面将通过示例代码演示,如何利用这个ini文件实现登录,和权限的认证

 public void t(){
        //设置使用的realm
        IniRealm iniRealm = new IniRealm("classpath:demo.ini");
        //新建一个安全管理器,并将realm设置到这个管理器中去
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);
        //将设置好的 安全管理器放入安全工具类中,然后用 安全工具类来获取subject
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        //创建登录用的token
        UsernamePasswordToken token = new UsernamePasswordToken();
        token.setUsername("xiezihao");
        token.setPassword("123456".toCharArray());
        //登录
        subject.login(token);
        if(subject.isAuthenticated()){
            System.out.println("登录成功");
        }

        if(subject.hasRole("admin")){
            System.out.println("拥有admin的身份");
        }

        if(subject.isPermitted("user.insert")){
            System.out.println("拥有 user.insert 的权限");
        }
    }

后面的例子其实都和这个比较的相似,都是按照如下顺序

  1. 拿到一个realm
  2. 用这个realm 设置出一个安全管理器
  3. 为安全工具类设置安全管理器,然后以此创建出subject
  4. 利用subject做后续的操作

自定义的realm

有的时候框架给出的realm不能满足我们实际的需求,我们可以自定义realm,新建一个类,让这个类去继承 AuthorizingRealm

然后实现里面的两个方法:doGetAuthorizationInfo 授权、doGetAuthenticationInfo 登录认证

下面用一个实际的例子 来说明

public class DemoRealm extends AuthorizingRealm {
    //授权的时候执行
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("开始鉴权操作");
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        HashSet<String> roles = new HashSet<>();
        HashSet<String> permissions = new HashSet<>();
        //将用户的角色和权限填入set集合  在实际的情况下这一步会从数据库中获取
        roles.add("admin");
        permissions.add("user.insert");
        
        //将用户的角色集合和权限集合放入到AuthorizationInfo中去
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }

    //登录时候执行
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("开始用户登录操作");
        //获取用户登录的用户名和密码
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        char[] password = usernamePasswordToken.getPassword();
        //这里我们模拟一下权限认证,实际情况上这里会从数据库拿数据
        if (username.equals("xiezihao") && new String(password).equals("123456")) {
            /**
             * 如果认证成功返回一个AuthenticationInfo对象,这三个参数分别是
             * 用户名、密码、和realm名字  realm的名字随便取好了主要是用来区分的作用
             */
            return new SimpleAuthenticationInfo("xiezihao", "123456", "demoRealm");
        }
        //如果登录失败就返回null
        return null;
    }
}

下面我们利用一个测试类来测试一下。测试类的写法可以参考 ini 这个测试的方法

@Test
    public void demoRealmT() {
        //	新建一个 我们自定义的realm
        DemoRealm demoRealm = new DemoRealm();
        //建立安全管理器
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(demoRealm);
        //构建 subject
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken();
        usernamePasswordToken.setUsername("xiezihao");
        usernamePasswordToken.setPassword("123456".toCharArray());
        //登录
        subject.login(usernamePasswordToken);
        if(subject.isAuthenticated()){
            System.out.println("用户已经成功登录");
        }

        if(subject.hasRole("admin")){
            System.out.println("用户拥有admin角色");
        }

        if(subject.isPermitted("user.insert")){
            System.out.println("用户拥有user.insert 操作的权限");
        }
    }

最后输出的结果如下

开始用户登录操作
用户已经成功登录
开始鉴权操作
用户拥有admin角色
开始鉴权操作
用户拥有user.insert 操作的权限

jdbc realm

前面的操作中我们使用的都是写死或者本地文件中写入用户配置,但是在实际的过程中我们肯定是从数据库中读取的

shiro提供了一个JdbcRealm 的类用来查询数据库,但是这个类里的sql 语句默认都是写死的,我们可以进入到这个类的源码里去看下

 /**
     * The default query used to retrieve account data for the user.
     */
    protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
    
    /**
     * The default query used to retrieve account data for the user when {@link #saltStyle} is COLUMN.
     */
    protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";

    /**
     * The default query used to retrieve the roles that apply to a user.
     */
    protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";

    /**
     * The default query used to retrieve permissions that apply to a particular role.
     */
    protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";

在这个类的开头定义了 这4个sql 语句,从上到下的用处分别是:

  • 用户账号密码登录
  • 用户带salt的账号密码登录
  • 查询用户名下所有的角色
  • 查询角色下所有的权限
    所以我们只需要把数据库的表按照这个sql 语句的形式来创建就可以了,但是这样子做肯定是不行的,因为实际的业务字段名可能不是这样的,所有我们可以重新自定义sql 语句,按照刚才源码里的格式 实际的操作请看下面的代码
@Test
    public void test(){
    	//设置一个数据库连接池,这里使用了阿里巴巴的druid连接池
        DruidDataSource source = new DruidDataSource();
        source.setUrl("jdbc:mysql://localhost:3306/rili");
        source.setUsername("root");
        source.setPassword("root");
        //创建一个jdbcrealm 并加你个连接池设置到这个realm中去
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(source);
        //自定义登录sql
        String sql = "select password from user where user_name = ?";
        jdbcRealm.setAuthenticationQuery(sql);
        //自定义角色sql
        String sql2 = "select quan from role where name = ?";
        jdbcRealm.setUserRolesQuery(sql2);
        //自定义权限sql
        String sql3= "select permission from permissions where juese = ?";
        jdbcRealm.setPermissionsQuery(sql3);
        /**
        * 这里是很重要的一句!必须要设置他为true,源代码里的解释是默认人false
        *  表示只有用户名和角色关联,如果要角色和权限关联必须设置为true
        */
        jdbcRealm.setPermissionsLookupEnabled(true);
       
       //之后的操作步骤就是和之前的一样就不再做复述了
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        securityManager.setRealm(jdbcRealm);
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("xiezihao","12345");
        subject.login(token);
        if(subject.isAuthenticated()){
            System.out.println("login ok");
        }
        subject.checkRoles("admin");
        subject.checkPermissions("user.update");

spring 整合shiro

到上面为止,介绍了shiro的基本使用方法,下面讲解的是如何将shiro和spring进行整合。

引入依赖

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

创建一个基本的springboot工程,引入必要的web依赖,这里关于springboot就不再做描述了

编写自定义realm

public class MyRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //获取登录的用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        //授权操作,模拟从数据库获取授权信息
        if (username.equals("admin")) {
            simpleAuthorizationInfo.addRole("admin");
            simpleAuthorizationInfo.addStringPermission("user:insert");
        } else {
            simpleAuthorizationInfo.addRole("default");
        }
        return simpleAuthorizationInfo;
    }

    //登入认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登录的用户名和密码
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());
        //认证,这里应该从数据库获取,为了简便就直接写了
        if (username.equals("admin") && password.equals("12345")) {
            return new SimpleAuthenticationInfo("admin", "12345", "MyRealm");
        } else {
            return null;
        }
    }
}

编写shiro 配置类

这里是重要的一步,定义一个类进行授权的配置

猜你喜欢

转载自blog.csdn.net/zjsxxzh/article/details/82938057