SpringBoot与Shiro整合权限管理实战

SpringBoot与Shiro整合权限管理实战

作者 : Stanley 罗昊

转载请注明出处和署名,谢谢!

*观看本文章需要有一定SpringBoot整合经验*

Shiro框架简介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,

从最小的移动应用程序到最大的网络和企业应用程序。

分析Shiro的核心API

其实,Shiro的核心类有三个,分别是:

1.Subject:这个类呢,我们称之当前用户的主体,这个用户的主体包含了登陆、注销等等的一些方法,还有一些判断授权的一些方法;

2.SecurityManager:这个名称翻译过来就是,安全管理器的意思;

3.Realm:这个Realm呢其实我们Shiro去链接数据库的一个桥梁,因为,我们的程序需要去操作数据库去获取一些用户的信息,这些操作都需要Realm去完成;

这个三个API呢,都存在一些关系,比如.SecurityManager是需要去关联我们的Realm,Subject是需要把操作交给我们的SecurityManager,总结下来就是,Subject是需要去管理我们的SecurityManager,而SecurityManager去关联我们的Realm;

以上就是对Shiro的核心API进行的一些分析;

分析完之后,我们接下来就直接用SpringBoot与Shiro的整合,我们来看下它整合的关键步骤

SpringBoot整合Shiro

那么这个整合首先第一步需要导入Shiro的依赖;

【因为我用的是Gradle,所以仅展示Gradle用法】

1.修改.gradle文件,添加以下依赖

//Thymeleaf模板引擎,因为我用模板引擎所以我添加了此依赖
        compile group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.11.RELEASE'
        //Shiro
        compile group: 'org.apache.shiro', name: 'shiro-web', version: '1.4.0'
        compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0'
        // https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring
        compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'

2.编写Shiro的配置类

配置类需要三样API,分别是:

 /**
     * 创建ShiroFilterFactoryBean
     * shiro过滤bean
     */

/**
     * 创建DefaultWebSecurityManager
     */

    /**
     * 创建Realm
     */

如图:

3.自定义Realm类

因为我们需要在配置类中创建出Realm对象,所以我们需要建一个名为Realm的类:

创建后,需要继承一个方法,这个方法是Shiro提供的:

/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    //执行授权逻辑
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        return null;
    }

    //执行认证逻辑
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
      
        return null;

    }

4.在配置类中new出Realm

 

Shiro配置配置类

package com.lh.shiroStudy.shiro;


import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;


/**
 * Shiro配置类
 */
//@Configuration,声明本类是一个配置类
@Configuration
public class ShiroConfig {

    /**
     * 创建ShiroFilterFactoryBean
     * shiro过滤bean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //添加Shiro过滤器
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *  常用的过滤器:
         *      anon: 无需认证(登录)可以访问
         *      authc: 必须认证才可以访问
         *      user: 如果使用rememberMe功能可以直接访问
         *      perms: 该资源必须得到资源权限才可以访问
         *      role: 该资源必须得到角色权限才可以访问
         */

        Map<String,String>filterMap = new LinkedHashMap<String, String>();
        //左边编写拦截路径
        filterMap.put("/add","authc");
        filterMap.put("/update","authc");
        filterMap.put("/testThymeleaf","authc");
        //授权过滤器
        //注意:当前授权拦截后,shiro会自动跳转未授权页面
        filterMap.put("/add","perms[user:add]");

        //修改跳转的登陆页面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

        //转跳至未授权页面【友好提示】
        shiroFilterFactoryBean.setUnauthorizedUrl("/aaaaaa");//懒省事所以没有aaaa这个页面,如果需要,请在Contoller中添加

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }


    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }



    /**
     * 创建Realm
     */
    @Bean(name = "UserRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }

}

Realm类

package com.lh.shiroStudy.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;


/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    //执行授权逻辑
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        //给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //添加资源的授权字符串
        //info.addStringPermission("user:add");

        //到数据库查询当前登陆用户的授权字符串
        /**
         * <!-演示状态-!>
         *     获取当前用户
         *     Subject subject = SecurityUtils.getSubject();
         *     User user = (User)subject.getPrincipal();
         *     User dbUser = userService.findById(id)
         *     info.addStringPermission(dbUser.getPerms());
         * </!-演示状态-!>
         */
        System.out.println("执行授权逻辑");
        return null;
    }

    //执行认证逻辑
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
        System.out.println("执行认证逻辑");
        //假设数据库账号与密码是如下
        String username = "admin";
        String password = "123456";
        /**
         * 编写Shiro判断逻辑,比对用户名和密码
         */
        //1.判断用户名
        UsernamePasswordToken token =(UsernamePasswordToken)arg0;

        //User user = userService.findByName(token.getUsername());

        if (user == null){
            //用户名不存在
            return null;//如果返回null,Shiro底层会抛出UnknowAccountException
        }
        //2.判断密码
        /**
         * 有三个参数
         * 1.需要返回给login
         * 2.是数据库的密码,将数据库密码返回,Shiro会自动判断
         * 3.是Shiro的名字
         */
        return new SimpleAuthenticationInfo(user,password,"");

    }
}

 

posted @ 2019-08-25 11:35  StanleyBlogs  阅读(1562)  评论(0编辑  收藏  举报