VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • SpringBoot整合Shiro权限框架实战

什么是ACL和RBAC#

ACL#

  • Access Control list:访问控制列表
  • 优点:简单易用,开发便捷
  • 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理
  • 例子:常见的文件系统权限设计,直接给用户加权限

RBAC#

  • Role Based Access Control:基于角色的访问控制
  • 权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限
  • 优点:简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来
  • 缺点:开发比ACL相对复杂
  • 例子:基于RBAC模型的权限验证框架,Apache Shiro

什么是Apache Shiro#

官网地址#

点我直达

介绍#

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

什么是身份认证#

  Authentication,身份认证,一般就是登陆校验

什么是授权#

  Authorization,给用户分配角色或者访问某些资源的权限

什么是会话管理#

  Session Management,用户的会话管理员,多数情况下是web session

什么是加密#

  Cryptography,数据加密,比如密码加解密

核心概念#

Subject#

  我们把用户或者程序称为主体,主体去访问系统或者资源

SecurityManager#

  安全管理器,Subject的认证和授权都要在安全管理器下进行

Realm#

  数据域,Shiro和安全数据的连接器,通过realm获取认证授权相关信息

Authenticator#

  认证器,主要负责Subject的认证

Authorizer#

  授权器,主要负责Subject的授权,控制Subject拥有的角色或者权限

Crytography#

  加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的API

Cache Manager#

  缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能

快速上手#

构建项目#

认证和授权#

QuickStartTest.java

常用API#

 
        //是否有对应的角色
        subject.hasRole("root");
        //获取subject名
        subject.getPrincipal();
        //检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断
        subject.checkRole("admin");
        //检查是否有对应的角色
        subject.hasRole("admin");
        //退出登录
        subject.logout();
 

QuickStartAPITest.java
pom.xml

realm实战#

作用#

  Shiro从Realm获取安全数据

概念#

  • principal:主体的标识,可以有多个,但是需要具有唯一性,如:手机号、邮箱
  • credential:凭证,一般就是密码

内置ini realm#

QuickStartIniTest.java
shiro.ini

校验权限#

QuickStartIniTest.java
shiro.ini

注:配置文件必须ini结尾

内置JdbcRealm#

方式一#

QuickStartJdbcIniTest.java
jdbcrealm.ini
建表语句.sql

注意#

  表名和字段要对应上,否则自定义定,继承:AuthorizingRealm,重写sql查询语句!!!!并重新指定realm类型!!!!

方式二#

QuickStartJdbc2Test.java

自定义realm#

  继承AuthorizingRealm重写授权方法doGetAuthorizationInfo重写认证方法doGetAuthenticationInfo

  UsernamePasswordToken:对应就是shirotoken中有PrincipalCredential

  SimpleAuthorizationInfo:代表用户角色权限信息

  SimpleAuthenticationInfo:代表该用户的认证信息

CustomRealm.java
QuickCustomRealmTest.java

Filter过滤器#

  • 核心过滤器
    • DefaultFilter,配置那个路径对应那个拦截器进行处理
  • authc:org.apache.shiro.web.filter.authc.FormAuthenticationFilter
    • 需要认证登录才能访问
  • user:org.apache.shiro.web.filter.authc.UseerrFilter
    • 用户拦截器,表示必须存在用户
  • anon:org.apache.shiro.web.filter.authc.AnonymoousFilter
    • 匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,一般用于过滤静态资源。
  • roles:org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
    • 角色授权拦截器,验证用户是否拥有角色
    • 参数可写多个,表示某些角色才能通过,多个参数时,写roles["root,role1"],当有多个参数时必须每个参数都通过才算通过
  • perms:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
    • 权限授权拦截器,验证用户是否拥有权限
    • 参数可写多个,表示需要某些权限才能通过,多个参数写perms["user,admin"],当有多个参数时必须每个参数都通过才算可以
  • authcBasci:org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
    • httpBasic,身份验证拦截器
  • logout:org.apache.shiro.web.filter.authc.LogoutFilter
    • 退出拦截器,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl(),设置的url
  • port:org.apache.shiro.web.filter.authz.PortFilter
    • 端口拦截器,可通过的端口
  • ssl:org.apache.shiro.web.filter.authz.SslFilter
    • ssl拦截器,只有请求协议是https才能通过

Filter配置路径#

  • 路径通配符支持?、*、**,注意通配符匹配不包含目录分隔符“/”
  • *:可以匹配所有,不加*,可以进行前缀匹配,但多个冒号就需要多个*来匹配
url权限采取第一次匹配优先的方式
?:匹配一个字符,如:/user?,匹配:/user1,但不匹配:/user/
*:匹配零个或多个字符串,如:/add*,匹配:/addtest,但不匹配:/user/1
**:匹配路径中的零个或多个路径,如:/user/**将匹配:/user/xxx/yyy

Shiro权限控制注解#

注解方式#

  • @RequiresRoles(value={"admin","editor"},logical=Logical.AND)
    • 需要角色:admin和editor两个角色,AND表示两个同时成立
  • RequiresPermissions(value={"user:add","user:del"},logical.OR)
    • 需要权限user:add或user:del权限其中一个,OR是或的意思
  • @RequiresAuthentication
    • 已经授过权,调用Subject.isAuthenticated()返回true
  • @RequiresUser
    • 身份验证或通过记住我登录过的

使用文件的方式#

  使用ShiroConfig。

编程方式#

SpringBoot整合Shiro#

技术栈#

  前后端分离+SpringBoot+Mysql+Mybatis+Shiro+Redis+JDK8

数据库表#

shiro_2.sql

项目结构#

CustomRealm.java
CustomSessionManager.java
ShiroConfig.java
AdminController.java
LogoutController.java
OrderController.java
OtherController.java
PublicController.java
VideoController.java
PermissionMapper.java
RoleMapper.java
UserMapper.java
Permission.java
Role.java
RolePermission.java
User.java
UserQuery.java
UserRole.java
CustomException.java
GlobalExceptiions.java
UserServiceImpl.java
UserService.java
JsonData.java
SpringbootShiroApplication.java
application.properties
Md5Test.java
pom.xml

项目源码#

链接: https://pan.baidu.com/s/1adjwICKge83YcPycE8ZaEQ  密码: if9s

项目postman测试#

 
127.0.0.1:12888/pub/index

127.0.0.1:12888/pub/not_permit

127.0.0.1:12888/pub/need_login

127.0.0.1:12888/pub/login

127.0.0.1:12888/authc/video/play_record

127.0.0.1:12888/admin/video/video_list

127.0.0.1:12888/video/add

127.0.0.1:12888/video/update
 

备注#

  因为链接较多,就不一一做gif动图了,直接导入项目源码,请求的时候,在header上加入token即可~

Filter过滤器#

业务需求#

  • 一个接口,可以让2个角色中的任意一个访问
  • 自定义一个类,继承:AuthorizationFilter
 
package com.ybchen.springboot_shiro.config;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.Set;

/**
 * @Description:自定义Filter
 * @Author:chenyanbin
 * @Date:2021/1/4 11:14 下午
 * @Versiion:1.0
 */
public class CustomRolesOrAuthorizationFilter extends AuthorizationFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        Subject subject = getSubject(request, response);
        //filterChainDefinitionMap.put("/admin/**", "roles[admin,user]"); mappedValue <==> admin,user
        String[] rolesArray = (String[]) mappedValue;
        if (rolesArray == null || rolesArray.length == 0) {
            return true;
        }
        Set<String> roles = CollectionUtils.asSet(rolesArray);
        //当前subject是roles中的任意一个,则有权限访问
        for (String role : roles) {
            if (subject.hasRole(role)) {
                return true;
            }
        }
        return false;
    }
}
 

 
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfig ShiroFilterFactoryBean 执行");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //如果访问需要登录的某个接口,却没有登录,则调用此接口(如果不是前后端分离,则跳转页面)
        shiroFilterFactoryBean.setLoginUrl("/pub/need_login");
        //shiroFilterFactoryBean.setLoginUrl("/xxx.jsp");
        //登录成功后,跳转的链接,若前后端分离,没必要设置这个
        //shiroFilterFactoryBean.setSuccessUrl("");
        //登录成功,未授权会调用此方法
        shiroFilterFactoryBean.setUnauthorizedUrl("/pub/not_permit");

        //设置自定义Filter
        Map<String, Filter> filterMap=new LinkedHashMap<>();
        filterMap.put("roleOrFilter",new CustomRolesOrAuthorizationFilter());
        shiroFilterFactoryBean.setFilters(filterMap);

        //拦截路径,必须使用:LinkedHashMap,要不然拦截效果会时有时无,因为使用的是无序的Map
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //key=正则表达式路径,value=org.apache.shiro.web.filter.mgt.DefaultFilter
        //退出过滤器
        filterChainDefinitionMap.put("/logout", "logout");
        //匿名可以访问,游客模式
        filterChainDefinitionMap.put("/pub/**", "anon");
        //登录用户才可以访问
        filterChainDefinitionMap.put("/authc/**", "authc");
        //管理员角色才能访问
//        filterChainDefinitionMap.put("/admin/**", "roles[admin,user]");
        filterChainDefinitionMap.put("/admin/**", "roleOrFilter[admin,user]");
        //有编辑权限才能访问
        filterChainDefinitionMap.put("/video/update", "perms[video_update]");
        //authc:url必须通过认证才可以访问
        //anon:url可以匿名访问
        //过滤链是顺序执行,从上而下,一般把/**,放到最下面
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
 

Redis整合CacheManager#

原因#

  授权的时候每次都去查询数据库,对于频繁访问的接口,性能和响应速度比较慢,此处可以使用缓存,提高响应速度,也可以使用Guava(本地内存缓存)。

  Redis(分布式缓存)还不了解的小伙伴,在这里我就不一一讲解了,可以看我以前写过的博客。

  • Redis 从入门到精通:点我直达
  • Redis 微信抢红包,电商场景下秒杀系统设计:点我直达
  • Redis 高级项目实战:点我直达

添加依赖#

 
        <!--shiro+redis-->
        <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>3.3.1</version>
        </dependency>
 

在ShiroConfig中添加如下代码

 
//使用自定义cacheManager
    securityManager.setCacheManager(cacheManager());

    /**
     * 配置redisManager
     * @return
     */
    public RedisManager getRedisManager(){
        RedisManager redisManager=new RedisManager();
        redisManager.setHost("127.0.0.1:6379");
        //连接那个数据库
        redisManager.setDatabase(0);
        //设置密码
//        redisManager.setPassword("123");
        return redisManager;
    }

    /**
     * 设置具体cache实现类
     * @return
     */
    public RedisCacheManager cacheManager(){
        RedisCacheManager redisCacheManager=new RedisCacheManager();
        redisCacheManager.setRedisManager(getRedisManager());
        return redisCacheManager;
    }
 

修改CustomRealm

设置redis缓存过期时间

Redis整合SessionManager#

为啥Session也要持久化#

  重启应用,用户无感知,可以继续以原先的状态继续访问。

修改shiroconfig

ShiroConfig.java

Shiro整合Redis后的源码#

链接: https://pan.baidu.com/s/1cNQfBiw50A-U5izzOQclpw  密码: 6wqt

 

来源:https://www.cnblogs.com/chenyanbin/p/shiro.html
 
 

相关教程