Jiiiiiin / jiiiiiin-security

本项目停止维护

Home Page:https://github.com/Jiiiiiin/jiiiiiin-security

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

⚠️ 项目停止维护,新项目关于springboot的一些工具库:https://gitee.com/yn_zhao_jun/piggy

jiiiiiin-security

基于SpringCloud微服务架构的开源网银(个人网上银行简化版)系统

原则

  • 以最少的表结构字段完成一个基础应用,以便在以此完成实际项目时有更多的扩充自由

如果你仅仅需要一个简单的内管系统,请切换到master分支,其仅仅是一个spring-boot前后端分离基础应用,当前分支,是用来学习和实践spring-cloud微服务框架所开

计划

  • SpringCloud

近期维护:新增feature/springcloud分支,将会在该分支尝试spring-cloud探索,目前基于第一代spring-cloud基础组件,核心为Netfix套件,进行一个初探

功能 完成状态 简介
docker化部署实践 0%
代码自动生成 50% 1.后端【单体应用】和【微服务应用】代码生成配置文档
TODO 2.前端代码生成(业务应用代码)
统一用户中心服务 90% 1.统一管理各个渠道的用户数据
统一用户认证中心服务 90% 1.统一对各个渠道提供标准的OAuth2身份认证服务
统一业务状态模块 90% 1.统一对各个渠道提供标准的OAuth2身份认证可访问上下文服务,即将access_token和redis认证用户数据做成各个服务可以直接访问的上下文
Eureka 服务注册发现 90% 1.服务注册和发现
2.注册中心-服务上下线
Zuul 服务网关 90% 1.权限控制
2.动态网关 目前因为apollo动态配置变更不能保证有序性存在一定瑕疵
3.动态限流
4.验证码校验
Feign/RestTemplate 服务间通讯和负载均衡 90% 1.服务间的调用
HYSTRIX/Turbine 服务的容错 90% 1.hystrix断路信息监控
Zipkin 服务链路追踪 90% 1.查看服务间调用链路数据
Spring Boot Admin 90% 1.通过eureka聚合各个服务的健康检查信息
apollo 服务配置管理 90% 1.集中式配置中心管理
2.实践动态日志
3.动态网关
4.开关驱动开发
5.灰度发布
6.动态限流
实践OAuth2授权认证中心 服务安全 90% 1.通过Spring Security Oauth2 + JWT来实现,身份认证通过网关走auth-center-server 统一用户认证中心服务
2.鉴权直接在网关的SpringSecurity Resource服务器完成,以解决SpringSecurity OAuth2默认的性能问题
Elastic Stack 50% 1.使用logstash-logback-encoder来完成结构化日志输出
2.使用Filebeat modules收集前端应用(如manage-app)的nginx访问和错误日志
3.使用Cerebro监控es集群状态
Swagger 100% 1.用来构建服务端的RESTFull Api接口,目前已经实现由网关统一接入,按服务进行分组查询
EasyMock 90% 1.持基于各个服务的Swagger接口创建对应的mock项目
RBAC后端权限控制 100% 1.基于Spring Security的后端RBAC权限控制
RBAC前端权限控制 100% 1.基于vue-viewplus,实现了一个自定义模块
2.实现前端页面可访问性控制,通过路由拦截,判断用户待访问页面是否已经授权
3.实现可见页面的局部UI组件的可使用性或可见性控制,基于自定义v-access指令,对比声明的接口或资源别是否已经授权
vue-viewplus一个简化Vue应用开发的工具库 100% 用于简化前端应用(如:manage-app)的开发工作
SpringMobile 100% 1.用来进行渠道判断,使得应用能根据请求的设备响应不同的数据格式
Gif验证码 100% 1.集成EasyCaptcha
2.集成kaptcha
SpringSecurity多渠道登录 100% 1.短信登录
会话并发控制 (browser单体模式下生效) 100% 使用SpringSecurity#concurrency-control实现应用中同一用户在同时只能有一个是终端(渠道)成功登录应用,后登录终端会导致前一个会话失效
会话集群共享 (browser单体模式下生效) 100% 使用Spring Session与Redis实现会话的共享存储和集群部署
记住我控制 (browser单体模式下生效) 50% 使用spring-security实现remember-me功能
集成druid监控 100% druid TODO 应该会换成默认数据库连接池,放弃druid
  • 业务

将会通过一个网上银行案例来实践服务划分

模块名称 完成状态 简介
用户服务 90% 统一用户中心服务
账户服务 0% 模拟电子银行账户模块
转账服务 0% 模拟电子银行转账业务模块

功能截图

以下是部分功能截图

nginx日志监控
Mock平台

项目结构说明

├── docs 文档
├── config
│   ├── apollo apollo对应应用配置文件
│   └── elk elk脚本
├── db 脚本目录
│   ├── init-db.sql 初始化脚本
│   ├── ApolloConfigDB_2019-07-05.sql apollo相关
│   ├── ApolloPortalDB_2019-07-05.sql apollo相关
│   ├── db_user_2019-08-16.sql 用户服务数据库脚本
│   └── db_account_2019-08-16.sql 账户服务数据库脚本
├── gateway-server 网关(通用服务)
├── metrics-service 监控服务(pom)
│   ├── hystrix
│   │   ├── hystrix-dashboard Hystrix熔断监服务(监控服务)
│   │   ├── hystrix-metrics-common Hystrix通用模块(lib)
│   │   ├── hystrix-turbine Hystrix Turbine聚合服务(聚合服务)
│   ├── spring-boot-admin-dashboard codecentric/spring-boot-admin监控服务
│   └── zipkin.jar zipkin监控服务
├── front-end-apps
│   └── manager-app 内管前端应用(vue项目,依赖d2-admin模块(1.6.9))
├── edge-service 边界服务(pom)
│   ├── auth-center-common 鉴权相关公共模块(lib)
│   ├── auth-center-server 统一用户认证中心服务
│   ├── easy-mock-app mock应用
├── middle-tier-service 后端服务(pom)
│   ├── business-lib 业务库
│   │   ├── business-common 业务公共库,存放各个服务公共代码(lib)
│   │   ├── business-status 统一业务状态模块,将access_token和redis认证用户数据做成各个服务可以直接访问的上下文
│   └── user 统一用户中心服务(pom)
│       ├── user-common 用户公共代码(lib)
│       ├── user-client 用户Feign客户端(lib)
│       ├── user-server 用户应用
│   ├── account 账户服务(pom)
│   │   ├── account-common
│   │   ├── account-server

微服务代码划分,以便更好的管理项目,另外模块约定也可以为做代码生成做准备

  • middle-tier-service为【原子服务】
    • 一个原子服务,有划分为:
      • 业务标识-client Feign客户端(提供给调用方使用)
      • 业务标识-server 服务本身
      • 业务标识-common 当前原子服务中client和server共同依赖的代码,如实体等
  • edge-service为【边界服务服务】
    • 边界服务即提供给外部客户端(如:App)来调用,组织比较自由,但有一个原则及其只会依赖【原子服务】,一般不作为内部服务提供者

即下图中的Edge ServiceMiddle Tier Service

关于边界服务和原子服务的理解可以参考,【微服务架构~BFF和网关是如何演化出来的】

快速开始

  • 视频演示

注意:目前该视频是针对master分支录制,等当前分支对spring-cloud实践有一个基础眉目我会在重新录制响应视频,但是这个视频对于user-server & manager-app也具有参考价值

Watch the video

下载高清视频

  • 提示步骤:

    • 修改本地hosts

      • win配置方法 | mac配置方法 | 建议使用 switchhost,开源群下载,对自己的网络环境自信的朋友,也可以直接官网下载

        # 本地测试环境
        127.0.0.1   js-redis
        127.0.0.1   js-mysql
        127.0.0.1   apollo-config-service-server
        127.0.0.1   apollo-portal-dashboard
        127.0.0.1   eureka-server
        127.0.0.1   hystrix-dashboard
        127.0.0.1   hystrix-turbine
        127.0.0.1   springboot-admin-dashboard
        127.0.0.1   zipkin-dashboard
        127.0.0.1   kibana-dashboard
        127.0.0.1   cerebro-dashboard
        127.0.0.1   user-server
        127.0.0.1   account-server
        127.0.0.1   auth-center-server
        127.0.0.1   gateway-server
        127.0.0.1   manager-app
        127.0.0.1   easy-mock-app
        127.0.0.1   router-server
    • 导入数据脚本

    • 启动jiiiiiin-mysql & jiiiiiin-redis

    • 启动apollo,并参考config目录中的xxx.properties创建各个应用的apollo对应项目或者直接导入sql脚本,并自行配置所需配置信息

    注意这里可以自行控制apollo的连接环境,可以使用apollo-Quick-Start快速上手实践

    • 启动eureka::DiscoveryServerApplication
    • 启动监控服务(可选)
    • 启动统一用户认证中心应用auth-center-server::AuthCenterApplication
    • 启动用户服务 user-server::UserApplication::9999
    • 启动网关 gateway::ZuulGatewayApplication::8861
    • 启动前端内管应用 manager-app::j manager-app && npm run serve
    • druid目前只有用户服务使用到,故监控直接导向到了其druid地址,用户名和密码查看对应配置

    一切ok,就可以直接访问manager-app 查看管理控制台了 :)

自定义配置

配置内容 位置
自定义properties配置jiiiiiin.security SecurityProperties.java 目前提供了针对公共接口、浏览器安全、验证码、OAuth2等相关配置
可覆盖的Bean配置 待整理~~

设计

总体设计

预期实践架构(来自微服务架构实战160讲)

  • 目前为了快速实现应用,调用链监控采用的是Zipkin
  • 指标监控用的是Spring Boot Admin

安全设计

js-oauth

上图简要描述了整个系统的安全相关设计,我们可以从上往下看:

  • 客户端应用发送身份认证请求

  • 请求通过网关直接发送到身份认证中心(OAUTH-CENTER-SERVER)

  • 身份认证中心通过FeignClient传递用户名或手机号到用户服务

  • 用户服务到数据库查询当前认证用户信息(基础信息、角色信息、资源信息、可访问接口信息),查询到之后返回给身份认证中心

  • 身份认证中心得到用户信息组装成一个认证通过的Authentication标识认证完成,并在此阶段将认证用户对象缓存到redis数据库这样的好处是,分离的资源和认证服务器后续都通过它来共享当前认证用户信息,**避免SpringSecurity OAuth的性能问题**

  • 并返回给客户端应用两个重要信息:TOKEN信息对象(包含访问令牌、刷新令牌和自建的身份认证对象存储在缓存数据库中的key cache_principal)和用户数据:

    类似:

    {
        "code": 0,
        "data": {
            "user": {
                "id": "1",
                "channel": "MNG",
                "username": "admin",
                "phone": "15399999999",
                "email": "15399999999@163.com",
                "roles": [
                    {
                        "id": "1061277220292595713",
                        "name": "系统管理员",
                        "authorityName": "ADMIN"
                    }
                ]
            },
            "oauth2AccessToken": {
                "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTg0MTA3MzksInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiI3NjA5YzU0Yi04NjJkLTRjNGMtYTVhNi0zNTBkYmJmZTgxN2MiLCJjbGllbnRfaWQiOiJwd2ViIiwic2NvcGUiOlsiYWxsIl19.1yKeKlHKzIo4cv1HY8ZqLbLP8LCeCJ5xkdFCL2MGSuE",
                "token_type": "bearer",
                "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiI3NjA5YzU0Yi04NjJkLTRjNGMtYTVhNi0zNTBkYmJmZTgxN2MiLCJleHAiOjE1NjA5OTU1MzksImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiMTU5OGJlZDYtMGZhMi00MDMwLWFhOWMtOGQxZWUzZDIwNzRkIiwiY2xpZW50X2lkIjoicHdlYiJ9.Zg39bkwSjT78HN3YN7_8F92URRicHp7D8oRVDnf5yX8",
                "expires_in": 7199,
                "scope": "all",
                "cache_principal": "tokenenhancer-userdetails-1"
            }
        },
        "msg": "执行成功"
    }
    

-w1180

  • 客户端应用,如前端内管应用 manager-app就会通过用户权限信息初始化前端rbac模块、缓存用户基础信息、缓存token信息(特别注意cache_principal

  • 到此认证完成,客户端应用在请求其他服务,如用户服务的修改当前用户密码接口,那么就需要在请求头携带两个重要信息:Authorizationcache_principal,且cache_principal被添加到了payload中,以便在请求通过网关到达背后的服务时,被访问服务能够通过该id获取到认证用户的信息,以解决一些通用需求;

  • 网关内部的资源服务器通过Authorization验证token有效性,针对鉴权,我们有两种思路:

    • 第一种情况,针对内管这类权限灵活运用,如需要RBAC权限处理,我们直接走.access("@rbacService.hasPermission(request, authentication)")自定义权限校验器来进行投票
    • 第二种情况,如果针对一般应用,如用户直接使用的商城这类应用,一般对于权限这块只会要求验证用户是否登录、或者是否是某个角色,那么我们就不会走)`自定义权限校验器
    • 这两种情况,就会影响到我们资源服务器在进行Authentication对象组装的时候,我们是否还需要去读用户缓存认证信息,即如果是第一种情况,因为权限要素过多我们必须要去缓存数据库重新加载一次,但是如果是第二种情况,我们直接通过JWT 访问令牌解析到的数据已经能够满足认证和鉴权需求就没必要再去加载一次,那反过来想想,我们在认证的时候也可以通过客户端应用渠道标识,来判断是否需要将认证信息缓存到redis,整个流程就变成下面这样,其实大多数应用应该都是这样:

js-oauth-simple

表结构和权限说明

db_user 用户中心库

表名称 简介
user 【用户表】,使用channel字段可以区分不同业务系统的用户,如这里0标识内管
role 【角色表】,使用channel字段可以区分不同业务系统的角色,如这里0标识内管
role_user 【角色用户关联表】,这套系统中,角色和用户是可以多对多配置的
resource 【权限资源表】,使用channel字段可以区分不同业务系统的资源,如这里0标识内管,另外type用来标识资源的类型,在这里只有类型: 1:菜单(默认) 0:按钮两种类型,并且没有直接定义一个类url字段取标识资源记录对应的后端某一个接口,是因为如一个菜单点击之后到达的页面可能要发多个后台交易,故一个字段来标识这多个交易容易导致混乱,所以在传统的RBAC表结构之下新增了interface【系统接口表】来定义,而资源则是给业务人员配置角色或菜单时使用;这张表还有一个特点是将前端Vue Router的页面路径以path字段标识,以方便前后端的权限管理
role_resource 【角色资源关联表】,用户、角色、资源都可以由业务人员进行关联操作
interface 【系统接口表】,使用channel字段可以区分不同业务系统的接口,如这里0标识内管,使用url+method来区分后台的某一个接口
resource_interface 【资源接口关联表】,resourceinterface是多对多关系,因为某一个接口,比如查询资源树接口在角色管理列表和资源管理列表两个页面都会被调用,且存在一个资源记录会调用多个接口,故我觉得这样来设计表机构,多加这一张表,才能更清晰的将意思表达到位,且方便维护
persistent_logins spring security 记住用户所涉及表
springsocial_UserConnection spring social 第三方授权信息关联表

db_account 网银账户库

TODO

问题汇总

  • 建议项目拉下来之后先clean compile package -Dmaven.test.skip=true一下,确保最后得到一个success,在进行其他操作,目前不保证测试用例是ok的,之后会修正
  • 针对这个依赖com.github.whvcse:EasyCaptcha找不到的问题,建议直接到对应厂库https://github.com/whvcse/EasyCaptcha将jar包拉下来通过命令导入到本地仓库即可,如:
mvn install:install-file -Dfile=/Users/jiiiiiin/Downloads/EasyCaptcha-1.5.0-RELEASE.jar -DgroupId=com.github.whvcse -DartifactId=EasyCaptcha -Dversion=1.5.0 -Dpackaging=jar

所用技术栈

后台

前端

参考

About

本项目停止维护

https://github.com/Jiiiiiin/jiiiiiin-security


Languages

Language:Java 94.2%Language:SCSS 2.3%Language:FreeMarker 2.0%Language:Shell 1.3%Language:Batchfile 0.2%Language:Python 0.1%Language:Dockerfile 0.0%