2021-01-06

陈彦斌博客园首页归档新随笔联系订阅管理
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:对应就是shiro的token中有Principal和Credential。

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 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 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 高级项目实战:点我直达
添加依赖#


org.crazycake
shiro-redis
3.3.1

在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/
关注: 点我哟(^U^)ノ~YO
个性签名:没有学不会的技术,只有不学习的人!
联系方式:543210188(WeChat/QQ),「推荐WeChat」
分类: Shiro, Spring Boot
联系方式
2
« 上一篇: Mac下安装Redis,附可视化工具Medis
posted @ 2021-01-05 23:07 陈彦斌 阅读(86) 评论(0) 编辑 收藏
登录后才能发表评论,立即 登录 或 注册, 访问 网站首页
Copyright © 2021 陈彦斌
Powered by .NET 5.0 on Kubernetes & Theme Silence v3.0.0
作词 : 无

作曲 : 无

李瑨瑶-Count On You

Written by :Bruno Mars

吉他:@李瑨瑶瑶瑶瑶

You can count on me like 123

I’ll be there

'Cause I know when I need it

I can count on you like 432

And you’ll be there

'Cause that’s what friends are supposed to do oh yeah

Oh yeah

You can count on me like 123

I’ll be there

And I know when I need it

I can count on you like 432

And you’ll be there

'Cause that’s what friends are supposed to do oh yeah

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值