码洞 - 后端
type: channel
link: https://www.tremblingboy.cn/index.php/category/background/
description: 万物归其本质
items: Docker + Jenkins + Gitee 实现自动 CI/CD
items: 国内使用阿里云 FC 对接 OpenAI API 方案
items: Spring Cloud披荆-Ribbon负载均衡-Feign声明式REST
items: Spring Cloud入门-Eureka注册中心
items: Spring源码解析（弃更）
items: 前后端项目快速整合Swagger
items: 权限框架Shiro快速整合前后端分离项目
items: 深入Shiro如何优雅的进行配置？
items: 初识Shiro有哪些需要注意的地方？
items: 基于RBAC模型的权限处理与MySQL建表

Docker + Jenkins + Gitee 实现自动 CI/CD
type: item
date: 2024-02-04T00:00:00+08:00
description: 开篇 为什么写这篇文章作为一名合格的全栈开发工程师（外加运维、UI设计……），在开发软件的时候，需要处理很多的事务，有些操作是频繁的、重复的、可程序化的，如果能通过脚本或工具来自动实现这些步骤，那开发者所操心的就只有如何写出高效可靠的代码了。 多人/多端开发环境诟病倘若是个单人小型项目，使用我之前文章中的实践方针已经基本可以达到目的。但是多人开发或者是大型的项目需要考虑到联调环境以及其他不同的情况如下：后端本地测试：考虑到电脑性能以及网络限制问题，不打算在本地跑数据库、缓存和消息队列等，需要远程云服务器。但是阿里云服务器限制性较多，经过测试发现 Mysql8 只能通过 SSH 连，否则不给本地回传数据。Redis 可以直连，但是可能会被服务器中断连接。前端本地测试：前端若要安装后端项目的环境，会比较麻烦，如果能直接在阿里云服务器上部署后端项目，前端再启动 node 访问服务器的接口，对于前端来说就是无感联调了。生产环境部署：当开发完一个 Release 版本后，需要发布到服务器部署，这个时候再使用前后端本地测试时的环境配置就不适合了，部分配置需要修改为 localhost 或者直接上域名。所以前后端都得准备至少两套配置。 抛砖引玉基于上面的情况，使用 Jenkins 实现自动化的持续集成就最好不过了，有了这个工具，后端写完项目只要提交到 git ，就会被监听触发构建，根据配置的命令上传到服务器网站目录下并实现自动部署，方便前端联调。若是生产环境也只需要修改打包的环境变量即可。所以写一篇文章来记录一下整个流程。 前提条件一个存储在 Gitee 的前后端分离项目一台配置还可以的云服务器（不够 4GB 内存构建前端可能会溢出） 实战 Jenkins 配置关于容器方面本篇不做教学，博主使用的是 1Panel面板，自带容器环境。默认端口8777进入，一路安装默认插件注册管理员账号。然后在插件页面根据实际需求下载所需的插件。Maven IntegrationGiteeNodeJSPublish Over SSH 403 问题处理如果容器部署的 Jenkins 遇到了 403 的问题，可以进容器内部，先装个 vim，再编辑 /usr/local/bin/jenkins.sh 文件，在 exec java这一行加上一个参数-Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true，解除跨站请求改造的拦截。（高版本引入的这个问题） 引入 Gitee 凭证直接进【系统管理】-【系统配置】，拉到下面填写 Gitee 相关信息和凭证。添加凭证点击后，获取方式如下图中的链接，转到码云里面生成一个 token。 Maven 安装由于是容器部署的，还要额外在容器里安装maven，或者直接用 Jenkins 自动安装。 NodeJs 安装为了加快国内依赖包下载速度，建议使用 cnpm 并添加淘宝镜像源，不过此镜像不是完全稳定，如果打包遇到问题，也可以考虑使用 yarn、pnpm，或其他镜像。cnpm --registry=https://registry.npm.taobao.org SSH 配置如果非容器化本地部署的 Jenkins，无需考虑这一步的操作，可以直接在后续的构建后置操作中写脚本来完成。但是对于容器部署的环境，以及源码、流水线、成果物三者不在同一个环境，则需要使用到SSH工具来远程连接并进行操作。我这个 Jenkins 版本不支持 pem 格式的密钥，所以需要使用 rsa 在容器内生成密钥，并将密钥填写至系统管理中。ssh-keygen -m PEM -t rsa -f id_rsa别忘了把公钥放到你要连接的服务器上。最后添加一个 SSH 服务并测试连接即可。 创建任务并配置返回首页点击新建任务后，选择构建一个maven项目由于上面配置了 Gitee 的凭证，这里就无需选择了，而且本来也选不到。只需填写代码仓库路径和打包分支。勾选 webhook 触发构建，并用这里的 url 在码云中创建。构建环境中需要选上 node，这样后续才能用之前配置的 cnpm 打包。同理配置 maven 打包命令。此处跳过 test，并且使用 prod 环境变量来匹配我的项目中的 application-prod.yml，请根据实际项目对应生产环境的打包命令填写。在构建后置操作中添加 shell 脚本来打包前端文件，具体脚本请根据实际来填写。例如你的 Jenkins 和部署的成果物在同一个环境，那么可以直接在这里打包完 dist 之后，将文件 cp 到网站运行目录下，并且通过 sh 脚本启动 Java 项目。由于我的 Jenkins 在容器中，所以后续通过 SS…

国内使用阿里云 FC 对接 OpenAI API 方案
type: item
date: 2023-05-10T13:12:00+08:00
description: 国内使用阿里云 FC 对接 OpenAI API 方案前言早在 ChatGPT 22 年 11 月底首次发布时，我就在第一时间体验了一把如今热的快要爆炸的人工智能。体验感就像老鼠舔了牛皮——属实牛批。之前元宇宙爆火的时候，我并没有太大的兴趣去参与，从程序员的角度上来看，这并不能成为一个突破性的技术，并且很难被推广和收到大众的喜爱。尽管在国外类似 Roblox 这类的元宇宙游戏，已经斩获接近 1kw 以上的用户的青睐，但在我看来这似乎只是一个 MMO + The Sim 的升级版。然而 ChatGPT 非同凡响，只是看了一言，就有一种：人类文明不存在了的感觉。尽管我在第一时间为此开发了软件，并且接入了人工智能，但是一个人的力量还是比不过团队，可以看到非常多原先的微信公众号，都开始卖课、卖会员、也有包装的非常好的换皮 GPT，最早一批变现的现在可能已经赚得盆满钵满了。GPT 并不 Open，而是逐渐 Close，限制登陆 IP，封禁批量注册用户……这也让我的脚步逐渐变缓。无论如何，我还是打算出一篇攻略，讲解一下国内的开发者们，如何以最稳健的方式在应用中对接 ChatGpt。前提你有阿里云账号你有 open ai 账号，且绑定了银行卡，能够正常调用 api下载代理包点击下载代理函数首先去 github 找到 openai-scf-prox 这是一个简易的代理程序，我们将使用他配合美区的云函数服务器，对国内请求进行反向代理，达到正常的调用目的。进入控制台进入阿里云函数计算FC控制台进入首页之后，一开始还不能选择地区，你会看到一些账号下的基础信息。创建服务进入【服务及函数】菜单，这里注意选择美区的地理位置，随便选一个地区即可，然后创建服务，随便填写名称。再点开高级选项，这里要创建一个阿里云的角色，并且分配 FC 的默认权限。其他的配置按照默认的即可（开日志功能和链路追踪要额外花钱）创建函数服务创建完成之后，就可以创建函数。选择【使用自定义运行时函数创建】->【处理HTTP请求】，运行环境推荐选比较稳定的 16，然后上传第一步里下载的代理包。在高级配置处，CPU 和内存全部选最小的，越小的免费调用额度越大 （好像是每月 1W 次？）并发度阿里云推荐压测后填写，代理包作者推荐填 2，我填的是 10，这块目前就自己用，没测试过。然后就可以创建了。集成到应用最后在触发器管理中，可以看到函数反向代理的 url。以 plexpt 的 java sdk 为例，填写触发器中的内网访问地址：以 openai 的 node sdk 为例：测试使用至此，一个简单的代理就完成了，国内网络均可快速调用 openai api。over！

Spring Cloud披荆-Ribbon负载均衡-Feign声明式REST
type: item
date: 2021-03-27T10:20:00+08:00
description: 开端目前主流的负载方案一般为两种：一种是集中式的负载均衡，在消费者和服务提供方中间使用独立的代理方式进行负载，有硬件（F5），也有软件（Nginx）。另一种则是客户端自己做负载均衡。我觉得使用Nginx也是一个不错的方式，但是这样我们还要令开一块专题去学习，既然在学Spring Cloud，我们就来试试使用Netflix开源的Ribbon做负载。另外ribbon的内容不是特别多，我们在此还会学习另一个知识点，声明式REST客户端Feign。Ribbon开始学习Ribbon。了解首先还是来了解一下Ribbon的基本模块：ribbon-loadbalancer：负载均衡模块，内置的负载均衡算法都实现在其中。ribbon-eureka：基于Eureka封装的模块，能够快速集成。ribbon-transport：基于Netty实现多协议的支持，比如HTTP、TCP、UDP等。ribbon-httpclient：基于Apache HttpClient封装的REST客户端，集成了负载均衡模块，可以直接在项目中调用接口。ribbon-example：代码示例，供学习。ribbon-core：核心且通用的代码，客户端API的一些配置和其他API的定义。使用浅尝结束初步的了解，咱们直接开始上手。关于我们之前Eureka的项目文件，大家可以放在一起，右键每一个pom文件后使用add as maven project功能构建。如此：这样一来就方便大家管理项目，以及统一启动和终止。我们首先复制一份eureka-client项目，创建一个消费者集群。启动类、控制层、配置文件、Maven文件的修改这里就不写了，都是些小细节。我将这个项目的端口设置为8084，然后启动，回到注册中心就可以看到集群成功。现在我们需要右键外面的大项目文件夹，重新创建一个ribbon-native-demo项目，创建方式同client。为pom添加依赖：<dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-loadbalancer</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>io.reactivex</groupId> <artifactId>rxjava</artifactId> </dependency>复制一份client的yml，修改应用名为ribbon-native-demo，端口为8083。然后写一个测试类调用hello接口。public static void main(String[] args) { List<Server> serverList = Lists.newArrayList( new Server("localhost", 8081), new Server("localhost", 8084) ); ILoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder() .buildFixedServerListLoadBalancer(serverList); for (int i = 0; i < 6; i++) { String result = LoadBalancerCommand.<String>builder() .withLoadBalancer(loadBalancer) .build() .submit(new ServerOperation<String>() { @Override public Observable<String> call(Server server) { try { String addr = "http://" + server.getHost() + ":" + server.getPort() + "/test/hello"; System.out.println("调用地址: " + addr); URL url = new URL(addr); HttpURLCon…

Spring Cloud入门-Eureka注册中心
type: item
date: 2021-03-17T10:02:00+08:00
description: 开端抛开别的不说，在这大学三年的时间里，我总是有意无意的回避开了一门技术，那就是Spring Cloud。因为它复杂繁多的模块而让我望而生畏，因为它永远排在我目标技术栈的最后一位。即使前继的技术栈基本已经粗略撸了个遍，我还是迟迟不敢在分布式服务上动刀子。想想我的大学生活也不久了，早晚要整活微服务，然后写我的毕业设计。So,Hi there,I'm TremblingBoy.了解在初步了解了微服务框架之后，我总结出了几点微服务的优劣之处：优点拆分项目，独立部署，耦合度低。也就是说不同服务之间不需要高度的依赖。快速启动，拆分的项目依赖库减少，代码量减少，启动速度必然加快。敏捷开发，发布新版本只需发布对应服务。高校代码复用，所有底层实现都可以以接口方式提供。缺陷更多的网络问题、容错问题、调用关系等。独立的数据库面临更多的挑战，尤其是事务的问题。测试难度提升，API的修改涉及到所有调用它的服务。运维难度提升，部署和监控变得非常复杂。总而言之，能量守恒，有得必有失，不可能存在完美无缺的代码，我相信微服务的少量缺陷，都能被它的大量优势所弥补。常用模块Eureka：服务注册中心，用于服务管理。Ribbon：基于客户端的负载均衡组件。Hystrix：容错框架，能够防止服务的雪崩效应。Feign：Web服务客户端，能够简化HTTP接口的调用。Zuul：API网关，提供路由转发、请求过滤等功能。Config：分布式配置管理。Sleuth：服务跟踪。Stream：构建消息驱动的微服务应用程序的框架。Bus：消息代理的集群消息总线。Boot复习要想使用Spring Cloud，有必要使用Spring Boot来简化操作。之前没有写过Spring Boot的文章，今天在这先简单创建一个Spring Boot项目吧，有机会咱们再整装待发杀入Spring Boot。准备首先准备好以下几个开发环境：JDK1.8（说实话还是8好用，我之前的开发环境用的11部署的时候好多问题）Maven（版本不规定了，用新的就好）IDEA（如果使用Eclipse请安装Spring Tools 4 for Eclipse和Lombok插件）创建项目咱们首先打开IDEA，创建一个Maven项目。先在pom里加个阿里的仓库。<repositories> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>设置JDK为1.8，加入spring-boot-maven-plugin插件，此插件可以将项目打包成jar文件直接启动。<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> 1.8 <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>添加启动包。<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>编写启动类，并且使用@SpringBootApplication注解标记启动类。package com.ky.kevin; import org.springframework.boot.SpringApplication; impo…

Spring源码解析（弃更）
type: item
date: 2021-03-05T13:53:00+08:00
description: 开端挺多技术都还是会过时的，但是Spring作为一套功能十分强大的全家桶框架，地位很难被撼动，甚至我已经后悔之前的项目使用了Shiro作为权限控制框架而不是Spring Security。原本是打算进军Spring Cloud，然后直接上手毕业设计，但是回顾我曾经的学习路线，挺多知识都只是囫囵吞枣式的学习，并没有一个系统、全面、深度的掌握。比如我是先学的Spring Boot，再去学的Spring，是不是挺奇葩的。这就和先学了三年级的方程求解，再去学一年级的加减法算术一样。我确实已经会用方程求解了，但是直接将两个数字放在等号同一边的这种正向思维式的解题方式还是没有学会，我只会反向思维的方程求解。如果要完全掌握计算，必须不管正反都理解它的原理才行。所以我才打算，重新来过，从Spring开始，吃透源码。所以这一方面我肯定会写很多篇博文，今天的全文都只算是一篇开端。The importance of 源码如果只是使用一个框架，那叫会看。但是如果能读懂源码，那叫会读。如果还能结合相关算法和设计模式，那叫会写。作为一位合格的Java后端架构师，需要具备有写框架这方面的能力。然而阅读源码费时费力，且普及程度非常差，许多简单的应用其实是环环相扣，层层嵌套得来的，并且还会遇到过于老旧而完全不清楚为什么要这么写的情况。无论如何，放弃阅读源码还是不明智的。俗话说，读万卷书，行万里路。其实各种框架之间也有很多共同之处，当你认真读完Spring的源码，或许理解其他框架会快很多。或许我写的内容并不会十分全面，毕竟写下这些最主要的还是为了做一个学习笔记。但是也希望读到这些博文的你会有所收获，因为写在这里的都是精华。核心实现整体架构Spring是一个分层框架，大约分为20个模块，总体可以归纳为以下几个部分。Core Container核心容器包含Core、Beans、Context、Expression Language模块，前两者为基础部分，提供IOC和依赖注入特性。Core：核心工具类，其他组件都需要用到。Bean：包含访问配置文件、创建管理Bean的类。Context：提供类似于JNDI注册器的框架式对象访问方法，继承了Beans的特性，支持J2EE，关键接口是ApplicationContext。Data Access/Integration该层包含JDBC、ORM、OXM、JMS和Transaction模块。Web该模块建立在应用程序上下文模块之上。包含以下几个模块：Web模块：使用servlet listener初始化IOC容器。Web-Servlet模块：包含MVC实现，使代码和web forms之间能够清楚地分离开。Web-Struct模块：提供了用于Portlet环境和Web-Servlet模块的MVC的实现。AOPAspects模块：提供对AspectJ的集成支持。Instrumentation模块：提供对class instrumentation和classloader的实现。容器基本用法如果说Spring是一个水桶，Beans就是水桶中的水，在正式开始源码分析之前，有必要了解一下其核心的两个类。DefaultListableBeanFactory这是加载Bean的核心部分，是Spring注册及加载Bean的默认实现，XmlBeanFactory继承自它并且使用了自定义的XML读取器XmlBeanDefinitionReader实现个性化读取。这个类的层次结构较为复杂，分为以下几个：AliasRegistry：定义对alias的简单增删改等操作。SimpleAliasRegistry：使用map缓存，实现AliasRegistry接口。SingletonBeanRegistry：定义对单例的注册及获取。DefaultSingletonBeanRegistry：对前一个类函数的实现。FactoryBeanRegistrySupport：在DefaultSingletonBeanRegistry基础上增加了对FactoryBean的特殊处理功能。BeanFactory：定义获取Bean及Bean的各种属性。HierarchicalBeanFactory：继承前一个类，增加了对parentFactory的支持。BeanDefinitionRegistry：定义BeanDefinition的增删改操作。ConfigurableBeanFactory：提供配置Factory的各种方法。ListableBeanFactory：根据各种条件获取Bean 的配置清单。AbstractBeanFactory：综合FactoryBeanRegistrySupport和ConfigurableBeanFactory的功能。AutowireCapableBe…

前后端项目快速整合Swagger
type: item
date: 2020-09-19T15:16:00+08:00
description: 开端Everybody，好久不见，因为开学的原因，已经拖更了半个多月。周末总算是闲下来写写博文，主要还是不想学习学校里教的那些东西。我们都知道，API 接口是一个非常神圣的内容。你做的好，前后端开发人员情同手足，和和美美；你做的不好，说不定他们每天一见面就要吵。在现在这个阶段，大家更倾向于使用一些已有的框架来进行API文档的开发，这样更加方便管理。尤其是动态更新 API 文档，更加省去了后端程序员一大部分的工作。在《阿里巴巴 Java 开发手册》中写到，API 文档和 Javadoc 就是为了方便他人阅读和理解程序而设计的，后端程序员若是更改了源代码而没有对应修改文档或注释，那文档和注释就没有了他们存在的意义。所以今天，我就来讲一个快速生成 API 文档的框架——Swagger。没错，他就是那么 Swag！以及如何整合到项目中去，包含了后端的注解生成器与前端嵌入式的页面显示方案。话不多说，那我们就开始吧。补充：实践过程中遇到特殊问题，请前往下方链接下载 dist 文件夹的内容并导入至项目文件中->Github Swagger-UI介绍为了解决前面讲到的问题，人们就提出了各种解决方案，方案用的人一多，就自成了一套体系，成了一套规范，这就是 Swagger 的由来。按照新的开发模式，只要每次更新 Swagger 的描述文件，就可以自动生成接口文档。但即便如此，仍旧需要开发人员每次修改 yml 或 json 文件。人都是有惰性的，久而久之就再一次忽略了描述文件的修改，导致更新不同步。因此急需更加简便的方案。所以作为Java届服务端的大一统框架Spring，迅速将Swagger规范纳入自身的标准，建立了 Spring-swagger 项目，后面改成了现在的 Springfox。在项目中引入 Springfox 之后，可以扫描代码并生成描述文件，同步接口文档，实现自动化管理。就目前来说已经是最重要且高效的几个生成接口文档的方式之一了。->点击链接了解Swagger整合介绍不多说，直接开始整合。关于阿里云仓库的使用我就粘贴我的另一篇文章中的内容，免得大家频繁跳转页面。使用阿里云仓库众所周知，如果你从 github clone 一个项目，如果没有梯子下载 jar 包可能就要花几个小时的时间。还好阿里爸爸给我们提供了镜像仓库，几分钟就能解决 jar 包的问题。关于引用仓库可以在 maven 配置中修改：<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>不过我还是推荐大家在自己的项目中加入仓库，灵活性更高：<repositories> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>这里我就直接用 public 仓库，这个仓库整合了两个小仓库，东西更丰富些。releases 是线上版本，snapshots 是开发版本，都填 true 问题不大。搜索并导入 jar 包->阿里云仓库大家可以在上边这个网址内搜索自己要找的 jar 包，中心 central 仓库够大了，输入文件名，点击搜索到的蓝色文件名后把 Maven 依赖这些代码复制进项目里即可。像下面的一样，我们引入最新版本的 Swagger 相关的 jar 包，如需拓展可以引用其他包。 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>io.springfox</groupId>--> <artifactId>springfox-swagger-ui</artifactId>--> <version>3.0.0</version>--> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-boo…

权限框架Shiro快速整合前后端分离项目
type: item
date: 2020-08-23T19:38:00+08:00
description: 开端好的，起因是我把最近做好的项目给一部分人进行了测试，发现大部分朋友都提出了同一个问题，你的系统权限管理是如何实现的。我只能尴尬的说一句，不好意思这部分还没开发。然而我也知道，其实对于一个项目来说，权限可以说是最主要的一部分。后端除了对权限进行处理，其实也就是提供一些业务逻辑对 CRUD 进行组合拼装。所以我打算接下来学习权限控制方面的知识并整合到我的项目中去，顺便把我的学习笔记分享给大家。而对于权限控制的框架呢，听的最多的还是 Shiro 还有 Spring Security。Spring 的安全框架单独用在 Spring 项目中是无可挑剔的，不管是功能上还是维护方面。但是考虑到 Shiro 是一个全能性的框架，可以用在各种场合，甚至非 Web 项目中，由于它的会话独立于容器，后期学习分布式和微服务的时候也比较方便使用。最重要的是 Spring 官网用的也是 Shiro 的框架。所以还是打算学习 Shiro。由于这部分内容比较多，我也发现了前后端项目部署那篇文章接近 1w 字导致阅读的时候不是很舒服，所以我打算把这个内容分成几个部分：初识 Shiro、配置重点、整合技巧来讲述。这篇文章是关于如何利用我们之前学习的知识快速进行 Shiro 与前后端分离项目的整合。虽然说是快速，我还是会一步步都告诉大家，并没有想象中的那么快。整合那么之前结果两篇长文的讲解，大家应该已经初步了解了一些关于 Shiro 的知识，接下来我们开始快速整合 Shiro 和 SSM ，我只讲最关键的步骤，至于更多额外功能的拓展留给大家自行发掘。下文的内容可能略微与我前面写的两篇文章有所不同，不过不影响食用。毕竟一边做一边写，总会发现之前的一些问题并找到更好的解决方法。使用 Maven 管理 jar 包Maven 是一个后端的包管理工具，可以使用写 XML 的形式快速从仓库寻找 jar 包。使用阿里云仓库众所周知，如果你从 github clone 一个项目，如果没有梯子下载 jar 包可能就要花几个小时的时间。还好阿里爸爸给我们提供了镜像仓库，几分钟就能解决 jar 包的问题。关于引用仓库可以在 maven 配置中修改：<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>不过我还是推荐大家在自己的项目中加入仓库，灵活性更高：<repositories> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>这里我就直接用 public 仓库，这个仓库整合了两个小仓库，东西更丰富些。releases 是线上版本，snapshots 是开发版本，都填 true 问题不大。搜索并导入 jar 包大家可以在上边这个网址内搜索自己要找的 jar 包，中心 central 仓库够大了，组织的话就是 Shiro 的网址，按结构写不要反了，然后输入文件名，点击搜索到的蓝色文件名后把 Maven 依赖这些代码复制进项目里即可。像下面的一样，我们引入最新版本的 Shiro 相关的 jar 包。具体使用哪些包的话请大家去官网上查找资料，比如说官网里提示说 core 包需要 slf4j 的支持，再比如说你用了谷歌的 IOC 容器，那么需要使用 guice 包等等。 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.5.3</ve…

深入Shiro如何优雅的进行配置？
type: item
date: 2020-08-15T17:39:00+08:00
description: 开端好的，起因是我把最近做好的项目给一部分人进行了测试，发现大部分朋友都提出了同一个问题，你的系统权限管理是如何实现的。我只能尴尬的说一句，不好意思这部分还没开发。然而我也知道，其实对于一个项目来说，权限可以说是最主要的一部分。后端除了对权限进行处理，其实也就是提供一些业务逻辑对 CRUD 进行组合拼装。所以我打算接下来学习权限控制方面的知识并整合到我的项目中去，顺便把我的学习笔记分享给大家。而对于权限控制的框架呢，听的最多的还是 Shiro 还有 Spring Security。Spring 的安全框架单独用在 Spring 项目中是无可挑剔的，不管是功能上还是维护方面。但是考虑到 Shiro 是一个全能性的框架，可以用在各种场合，甚至非 Web 项目中，由于它的会话独立于容器，后期学习分布式和微服务的时候也比较方便使用。最重要的是 Spring 官网用的也是 Shiro 的框架。所以还是打算学习 Shiro。由于这部分内容比较多，我也发现了前后端项目部署那篇文章接近 1w 字导致阅读的时候不是很舒服，所以我打算把这个内容分成几个部分：初识 Shiro、配置重点、整合技巧来讲述。这篇文章是关于 Shiro 该如何配置的，面向 Spring Boot，讲一些比较基础的内容。深入Shiro之前我们了解了一下 Shiro 的基本功能和架构，现在我们来看看它的工作流程。工作流程拦截Shiro 特别重要的一块就是拦截，它通过过滤器拦截所有请求，根据配置决定哪些可以认证通过，哪些不用被拦截，还有哪些没有通过认证强制跳转。我们看一段配置代码，如何通过过滤器决定谁去谁留。@Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/user/login"); Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/user/login","anon"); filterChainDefinitionMap.put("/**", "corsAuthenticationFilter"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); Map<String, Filter> filterMap = new LinkedHashMap<>(); filterMap.put("corsAuthenticationFilter", corsAuthenticationFilter()); shiroFilterFactoryBean.setFilters(filterMap); return shiroFilterFactoryBean; }代码非常简单，首先使用 @Bean 注释将这个方法交给 Spring 来管理，名字必须是 shiroFilter，这样才能和默认配置中的名字匹配，否则 Spring 会找不到这个过滤器。在这个方法中首先 new 一个过滤器工厂对象，将获取到的 securityManager 注入。之后设置一个登陆 url，告诉 Shiro，这个页面/接口是我的登陆页面，用户角色权限的获取也都在这里。接着就是刚刚图中的 filterChainDefinition，我们定义一个 map 来存储不被拦截的页面。每一个键值对中 key 存储 url，value 存储拦截器的名字，拦截器主要是以下几个：拦截器名称拦截器功能anno不需要授权和登录，可以匿名访问authc需要登录授权才能访问logout退出成功之后可以自定义重定向user需要登录授权或者登录后开启了记住我（remember me）就能访问ssl通过https协议才能通过roles角色拦截restrest风格拦截port端口拦截perms权限拦截noSessionCreation不创建会话连接器authcBasic基本http身份验证拦截比较常用的四个拦截器我使用加粗表示出来了，anno 一般是最先使用…

初识Shiro有哪些需要注意的地方？
type: item
date: 2020-08-12T19:28:00+08:00
description: 开端好的，起因是我把最近做好的项目给一部分人进行了测试，发现大部分朋友都提出了同一个问题，你的系统权限管理是如何实现的。我只能尴尬的说一句，不好意思这部分还没开发。然而我也知道，其实对于一个项目来说，权限可以说是最主要的一部分。后端除了对权限进行处理，其实也就是提供一些业务逻辑对 CRUD 进行组合拼装。所以我打算接下来学习权限控制方面的知识并整合到我的项目中去，顺便把我的学习笔记分享给大家。而对于权限控制的框架呢，听的最多的还是 Shiro 还有 Spring Security。Spring 的安全框架单独用在 Spring 项目中是无可挑剔的，不管是功能上还是维护方面。但是考虑到 Shiro 是一个全能性的框架，可以用在各种场合，甚至非 Web 项目中，由于它的会话独立于容器，后期学习分布式和微服务的时候也比较方便使用。最重要的是 Spring 官网用的也是 Shiro 的框架。所以还是打算学习 Shiro。由于这部分内容比较多，我也发现了前后端项目部署那篇文章接近 1w 字导致阅读的时候不是很舒服，所以我打算把这个内容分成几个部分：初识 Shiro、配置重点、整合技巧来讲述。这篇文章是关于初识 Shiro 的，主要是 Shiro 的一些基本特性和架构，以及官网上的小例子。 # Shiro 简介Apache 软件基金会开发的 Java 安全（权限）框架。适用于 Java SE 和 Java EE 的环境。主要功能有：认证、授权、加密、会话管理、集成 Web、缓存等。[官网下载]: shiro.apache.org Shiro 具体功能功能翻译解释Authentication身份验证/登录验证用户登录时的身份Authorization权限验证验证用户拥有哪些权限Session Manager会话管理一次登录即一次会话Cryptography加密保护数据安全，密码加密存储Web SupportWeb支持支持方便的Web集成Caching缓存提高查找效率Run As身份替换假装成其他用户(若被允许)Remember Me二次记忆二次登录无需验证初次见面看不懂没有关系的，现在心中有个初步的印象，等到全部学习完整合完你就恍然大悟了。我就简单的讲两个：Authentication首先前两个功能比较容易混淆，到时候写程序千万看清别把方法名写错。Authentication 是身份的验证，我们对于权限的结构划分是基于 RBAC 模型来的（具体可以见我的另一篇博文），所以会有用户、角色、权限三层数据表。而这个功能就是判断用户的角色，是管理员、运维、开发还是测试等等。我们来看一段 Realm 中的方法 doGetAuthenticationInfo：@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String userName = token.getUsername(); User user = userService.selectByName(userName); return new SimpleAuthenticationInfo( user.getUsrName(), user.getUsrPassword(), getName() ); }这段方法中首先获取用户身份 token 参数，然后获取用户名。使用我自定义的 Mapper 中的 selectByName( ) 在用户数据表中查询数据，最后返回一个 Simple 身份验证信息，参数为用户名、密码和 CachingRealm 的名字。当然正统的方式是把用户对象直接传给他，但是我测试的时候发现传用户名和密码出错的可能性更低，具体可以去看看 SimpleAuthenticationInfo 类的源码。Authorization第二个是用来验证角色所对应的权限。比如说管理员用户拥有增删改查所有权限，游客只拥有查找的权限等等。我们还是通过一段 Java 代码来理解这个功能。@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizatio…

基于RBAC模型的权限处理与MySQL建表
type: item
date: 2020-08-11T15:20:00+08:00
description: 开端其实这不是个开端，是我在写 Shiro 整合 SSM 的时候写不下去了，想重新开一篇来写。。。高考语文 80 分，实在憋不出来写啥了啊哈哈哈。emmm 回归正题，这次我们来讲一讲 RBAC 模型的权限处理，以及基于这个模型我们该如何设计数据表。我在刚做项目的时候其实完全没有考虑到这块内容，我觉得权限只要一个用户一个角色，前端根据用户登录时获取到的角色信息进行接口的放行或者禁止就可以了。仔细想一想确实有很多漏洞，比如我直接使用 Postman 对一些需要权限才能调用的接口进行访问等等；再比如我的 token 是前端直接生成的，而没有利用 session、cookie 等技术，如果有人直接往自己浏览器的 sessionStorage 里存一个管理员 token 不就可以获得最高权限了吗，这显然是不可取的。权限，应当是一个系统最先进行考虑的，之后才是在权限的基础上 CURD CURD CURD 。。。我们先来看看对权限模型的思考吧。解析接下来进入正题。权限模型首先来分析一下我们目前比较常用的一些权限模型。传统权限模型一般来说的传统权限模型并没有什么复杂的内容，就是我开头讲到的最基本的用户和权限之间的绑定。我数据库里存了三个用户，那么给每个用户都分配各自的权限。但是业务复杂起来，用户多起来之后就会发现问题了。这样的方式绑定权限，删改不够灵活。用户不可能每个人的权限都各不相同，总有一些相同类别的用户，他们需要相同的权限。比如说管理员老王和其他管理员都要拥有系统所有的权限，这样才能方便测试接口，如果管理员都没有权限，这个操作还有什么意义。再比如吃瓜群众这类人，他也就只能登陆系统查查基本的数据，对于修改尤其是添加和删除是完全没有任何权限的，修改也仅限于自己的头像啊密码啊什么的。那当一类人到达一定基数的时候，我们是不是可以将他们的角色给抽离出来，独自形成一层。这就是我接下来讲到的 RBAC （Role-Base Access Control）。RBAC0 权限模型按照英文来解释，就是基于角色的权限控制。所以显而易见，他在传统的权限模型里又加了角色。我们在传统模型中是直接将权限赋予用户。而在这个模型中，现将权限赋予角色，再把角色赋予用户，这样的分层是不是就更加清晰了。就和学校里一样，校领导管一批院领导，院领导管各自的年级专业，每一个年级专业再分班分学号给每一位同学。和我既是属于计算机专业的，又是属于机电系的是一个道理。但是我这个图其实还有点问题，大家可以发现我画的每一个用户只对应了一个角色，在实际操作中往往是用户和角色之间是一对多的关系，而且同一角色内部也有细分。试想一下，如果老王和老贾都是管理员，但是老王等级更高一些。老贾只是个新来的，但是他们所拥有的权限是一样的。老王是不是就有意见，万一哪天老贾一个删库到跑路把锅甩给老王那可咋办？所以接下来又在这个基础上派生出几个不同的权限模型。RBAC1角色分层模型为了解决老王内心的不愉快，我就只能给管理员分成两个等级，其他角色也同样操作。这样一来，我可以通过同一角色之间不同等级的权限分级，给他们分配不同的权限。换一种角度来说这其实和多分配了几个角色没有区别，但是给角色分级之后同一角色不同等级之间耦合度更高一些，可能只有少数权限不相同。随着角色的增多，分级的增加，问题又来了。吃瓜群众中奖被选为我们软件的内测人员，终于可以从普通低级用户变为低级检错员了，但是他作为普通用户的一些权限仍旧保留，那该怎么办？所以接下来又有一种权限模型的想法诞生了。RBAC2 角色限制模型这种模型比较难用图来表示，简单的来说就是可以限制一个用户拥有多个角色的时候只能同时激活一个角色，或者用高级的角色包含住低级的角色，然后规定用户必须从低级角色升级到高级角色，仅保留高级角色的权限。完全应用这种模型的场合并不太多。RBAC3 统一模型RBAC3 = RBAC2 + RBAC1这种模型是前两种的结合体，相对来说更加复杂，很少会考虑这么做，就不多赘述。模型的选择其实对于一个系统来说，权限是根据需求来定的，并不是一定要按照上述的几种来写，每一种权限模型都有它的特点，有优势有缺陷。所以我们在开发的时候，要根据自己的项目来确定权限模型。就好比我自己做的小项目比较简单，没有涉及很多用户。所以就只设置了管理员、学生、教师三种不同的角色，然后每一个用户只能同时激活一个角色，最后再给每个角色分配权限。MySQL建表对于 Shiro 下的权限数据表，一般来说比较正规的都是采用权限五表。首先用户数据肯定需要一张表来存，其次是权限数据的一张表。当我们采用 RBAC 模型时，角色也需要一张表来存。那么如何将这三张表之间相互关联呢，我们就需要另外的一张用户-角色表，以及一张角色-权限表，可以将主要的三张表之间的主键一一关联起来。我们就来看一下这五张表的建表语…