Spring Cloud 保证微服务内安全

一、简介 在微服务的架构下,我们需要把系统的业务划分成多个单一的微服务。每个微服务都会提供接口供其他微服务调用,在Dubbo中可以通过rmi、nio等实现,Spring Cloud中是通过http调用的。但有些时候,我们只希望用户通过我们的网关调用微服务,不允许用户直接请求微服务。这时我们就可以借助Spring Security来保障安全。 二、使用步骤 2.1 在提供接口的微服务项目中配置Spring Security 1 首先在pom.xml引入Spring Security的相关配置,如下 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 2 在qpplication.yml中配置账号密码,如下 security: basic: enabled: true user: name: sunbufu password: 123456 3 此时访问接口发现已经需要认证了。 输入正确的账号和密码后就可以访问了。 2.2在调用微服务项目中配置Feign的账号密码 1 在application.yml中配置账号密码 security: user: name: sunbufu password: 123456 2 添加Feign的配置文件 package com.sunbufu.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.auth.BasicAuthRequestInterceptor; @Configuration public class FeignConfiguration { @Value("${security.user.name}") private String userName; @Value("${security.user.password}") private String passWord; @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){ return new BasicAuthRequestInterceptor(userName, passWord); } } 3 这样完成后,就可以正常的访问了。 三、实例 源码地址...

June 13, 2018 · 1 min · sunbufu

Spring StateMachine介绍

一、状态机 有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在电商场景(订单、物流、售后)、社交(IM消息投递)、分布式集群管理(分布式计算平台任务编排)等场景都有大规模的使用。 状态机的要素: 状态机可归纳为4个要素,现态、条件、动作、次态。“现态”和“条件”是因,“动作”和“次态”是果。 现态:指当前所处的状态 条件:又称“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必须的,当条件满足后,也可以不执行任何动作,直接迁移到新的状态。 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转换成“现态”。 状态机动作类型: 进入动作:在进入状态时进行 退出动作:在退出状态时进行 输入动作:依赖于当前状态和输入条件进行 转移动作:在进行特定转移时进行 二、spring statemachine spring statemachine是使用 Spring框架下的状态机概念创建的一种应用程序开发框架。它使得状态机结构层次化,简化了配置状态机的过程。 官方文档:https://docs.spring.io/autorepo/docs/spring-statemachine/1.0.0.M3/reference/htmlsingle/#sm-statecontext 例子一:简单订单状态 源码已经上传到github。 如下所示: 1 引入依赖 <!--spring statemachine--> <dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>spring-statemachine-core</artifactId> <version>2.0.1.RELEASE</version> </dependency> 2 创建订单状态枚举类和状态转换枚举类 /** * 订单状态 * * @author sunbufu */ public enum OrderState { /** 待支付 */ WAIT_PAYMENT, /** 待发货 */ WAIT_DELIVER, /** 待收货 */ WAIT_RECEIVE, /** 完结 */ FINISH; } /** * 订单事件 * * @author sunbufu */ public enum OrderEvent { /** 支付 */ PAYED, /** 发货 */ DELIVERY, /** 收货 */ RECEIVED; } 3 添加配置 /** * 订单状态机配置 * * @author sunbufu */ @Configuration @EnableStateMachine(name = "orderStateMachine") public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> { @Override public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception { states....

June 13, 2018 · 3 min · sunbufu

单元测试

1. Mockito 单元测试开发中,我们经常会遇到测试的类有很多依赖的类、对象、资源,从而形成巨大的依赖树,mock可以模拟外部依赖,适应单元测试。 比如我们在开发中很容易出现这种情况: (a)依赖(b)依赖(c)依赖(d) 这种情况下单元测试就变得极其复杂,而且如果需要测试数据库或网络请求返回值的情况,就更加复杂了。我们总不至于去修改真实数据库,去修改真实的网络情况吧。 但是如果我们引入Mockito情况就会变得简单许多,我们可以mock虚拟的依赖,并可以轻松的修改返回值甚至抛出异常: (a)依赖(mock b) 1.1 Mockito 的简单用法 Mockito是一个功能非常丰富的框架,下面介绍几个典型和常用的方法,详细的使用可以到官网上查询。 Mockito官网{:target="_blank"} Mocktio文档{:target="_blank"} 我们在非Spring Boot项目中使用Mockito需要手动引入依赖,Spring Boot项目中Mocktio的使用会在下面介绍。 <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> 1.1.1 mock对象 // 模拟LinkedList 的一个对象 LinkedList mockedList = mock(LinkedList.class); // 此时调用get方法,会返回null,因为还没有对方法调用的返回值做模拟 System.out.println(mockedList.get(0)); 1.1.2 方法调用的返回值 // 模拟获取第一个元素时,返回字符串first。 给特定的方法调用返回固定值在官方说法中称为stub。 when(mockedList.get(0)).thenReturn("first"); // 此时打印输出first System.out.println(mockedList.get(0)); 1.1.3 方法调用抛出异常 // 模拟获取第二个元素时,抛出RuntimeException when(mockedList.get(1)).thenThrow(new RuntimeException()); // 此时将会抛出RuntimeException System.out.println(mockedList.get(1)); 如果一个方法没有返回值类型,那么可以使用此方法模拟异常抛出 doThrow(new RuntimeException("clear exception")).when(mockedList).clear(); mockedList.clear(); 1.1.4 调用方法时的参数匹配 // anyInt()匹配任何int参数,这意味着参数为任意值,其返回值均是element when(mockedList.get(anyInt())).thenReturn("element"); // 此时打印是element System.out.println(mockedList.get(999)); 1.1.5 验证方法调用次数 // 调用add一次 mockedList....

June 13, 2018 · 4 min · sunbufu

发布jar包到maven中央仓库

一、写在前面 最近做了一个权限认证的框架,想把jar发布到maven中央仓库上,方便大家使用。于是就有了这篇博客。 二、具体步骤 2.1 注册账号 首先要做的就是注册账号,这个账号可用于提出申请groupId的Issue,也可用于发布和登录到中央仓库。 2.1.1 注册sonatype 工单地址:https://issues.sonatype.org 2.2 申请groupId 创建申请groupId的工单 工作人员会审核你的申请,如果你的groupId是你的域名,还需要提供一些证明。如果没有域名也可以使用一些开源网站,例如com.github.xxx,io.github.xxx等。 如果审核时间很长的话,可以尝试再次提交一个工单。工作人员在审核的时候可能根据最近的Issue来的。 2.3 配置GPG 这次我用的mac,所以我使用brew安装的gpg。 brew install gpg 然后建立软连接到/usr/local/bin/ sudo ln -s /usr/local/Cellar/gnupg/2.2.7/bin/gpg /usr/local/bin/gpg 因为我使用的版本是2.2.7,加密多次失败后。网上查到需要进行一些额外配置。 在gpg的安装目录(~/.gnup)下新建两个配置文件: gpg.conf: use-agent pinentry-mode loopback gpg-agent.conf: allow-loopback-pinentry 2.4 生成秘钥 执行命令,并填入一些信息后生成秘钥 gpg --gen-key gpg --list-keys pub rsa2048 2018-05-18 [SC] [有效至:2020-05-17] xxxxx uid [ 绝对 ] sunbufu <sunyoubufu@qq.com> sub rsa2048 2018-05-18 [E] [有效至:2020-05-17] 发布公钥到服务器 gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys xxxxx 2.5 配置settings.xml 首先需要配置用户名和密码(2.1.1中注册的用户名和密码) <server> <id>ossrh</id> <username>用户名</username> <password>密码</password> </server> 2....

June 13, 2018 · 1 min · sunbufu

快速排序的Java实现

快速排序是目前所有排序中性能较好的一种算法,最好情况和平均情况下时间复杂度均为O(nlogn),最坏的情况下时间复杂度为O(n^2)。快速排序采用递归,用空间换取时间。由于使用了递归,因此需要额外的存储空间。 package sunbufu.sort; import java.util.Arrays; public class MyQuickSort { public static void main(String[] args) { int[] array = { 2, 5, 1, 4, 3, 9, 5, 1, 12 }; System.out.println(Arrays.toString(array)); System.out.println("--------------------------"); quickSort(array, 0, array.length - 1); System.out.println("--------------------------"); System.out.println(Arrays.toString(array)); } private static void quickSort(int[] array, int low, int high) { int l = low; int h = high; int key = array[low];// 默认选择第0个为基数 while (l != h) {// l跟h相等则结束 while (l < h && array[h] >= key)// h从右向左移动,直到找到一个比基数小的值 h--; if (l < h) swap(array, l, h); while (l < h && array[l] <= key)// l从左向右移动,直到找到一个比基数大的值 l++; if (l < h) swap(array, l, h); } // 然后把数组从基数所在的位置分成两部分,分别递归 if (l > low) quickSort(array, low, l - 1); if (h < high) quickSort(array, h + 1, high); } private static void swap(int[] array, int a, int b) { int temp = array[a]; array[a] = array[b]; array[b] = temp; System....

June 13, 2018 · 2 min · sunbufu