heroku_使用heroku快速构建多租户saas启动部分1

heroku

[In this multi-part series, I’ll transform a new application into a multi-tenant experience running in the Heroku ecosystem. This article focuses on the object model, design, architecture, and security.]

[在这个由多个部分组成的系列中,我将把一个新的应用程序转换为在Heroku生态系统中运行的多租户体验。 本文重点介绍对象模型,设计,体系结构和安全性。]

My wife, Nicole has an identical twin named Danyel. While Nicole and Danyel have always maintained their individuality, they both share a passion for being in good physical shape and sticking to a workout routine. In fact, Danyel decided to build upon her fitness passion and start training others out of her personal gym located in the Las Vegas area. While hearing about the tasks Danyel worked through getting her business started (i.e. permits, legal documents, and insurance), I asked about her plan to keep track of her business.

我的妻子妮可(Nicole)有一个同卵双胞胎,名字叫Danyel。 妮可(Nicole)和丹妮尔(Danyel)始终保持自己的个性,但他们都对保持良好的身体状态和坚持日常锻炼充满热情。 实际上,丹尼尔(Danyel)决定增强对健身的热情,并开始从位于拉斯维加斯地区的私人健身房中训练其他人。 当听到Danyel开展业务的工作任务(即许可证,法律文件和保险)时,我询问了她跟踪业务的计划。

Long story short, Danyel had been focused on getting her business running, but wasn’t focused on having the necessary technology in place to meet the needs of her business. Since I am fresh off a successful conversion of my mother-in-law’s application from Amazon Web Services (AWS) to Heroku (see Heroku — My New Home), I thought it was time to pitch in and help Danyel’s business from an application perspective.

长话短说,Danyel一直专注于使其业务运转,但并不专注于拥有必要的技术来满足其业务需求。 由于我刚从婆婆的应用程序成功地从Amazon Web Services(AWS)转换到Heroku(请参阅Heroku ,我的新家),所以我认为是时候从应用程序角度介入并帮助Danyel的业务了。

After a couple video calls and a quick visit to the Las Vegas area, we had determined that the new fitness application would provide the following features in the initial release:

经过几次视频通话并快速访问了拉斯维加斯地区,我们确定新的Fitness应用程序将在初始版本中提供以下功能:

  • Client management (to manage her customers)

    客户管理(管理她的客户)
  • Workout management (to create routines for her customers to perform)

    锻炼管理(为客户创建例程以执行)
  • Session management (to create workout sessions which consist of a workout and for at least one customer)

    会话管理(创建包含一个锻炼并且至少为一个客户组成的锻炼会话)

Looking ahead, I later mapped out this chart of future functionality:

展望未来,我后来绘制了此未来功能表:

While showing the progress of the application to Nicole, she casually asked, “I wonder how many other personal trainers might be interested in having an application like the one you are building for my sister?”

在向妮可展示申请的进度时,她随便问道:“我想知道还有多少其他私人教练对像您为我的妹妹建造的这样的申请感兴趣吗?”

Nicole’s question sparked me to alter my design and create a system that could be used by more than just her sister. Nicole’s comment transformed my design from a simple application that would run in Heroku to a multi-tenant application that could be utilized by multiple fitness trainers, regardless of location. From that point, I started thinking of the application in terms of a Salesforce-like experience for personal trainers.

妮可的问题促使我改变了自己的设计,并创造了一个不仅可以被妹妹使用的系统。 Nicole的评论将我的设计从可以在Heroku中运行的简单应用程序转变为可以由多个健身教练使用的多租户应用程序,而不论其位置如何。 从那时起,我开始根据针对私人教练的Salesforce体验来考虑该应用程序。

From a technical perspective, I wanted to see just how quickly and easily I could build a SaaS solution to be used by more than one fitness trainer. From a business perspective, this solution would allow fitness instructors to not only manage their clients, workouts, and sessions, but become a single point of reference for all aspects of their business — all for a low monthly rate.

从技术角度来看,我想了解如何快速,轻松地构建一个SaaS解决方案,以供多个健身教练使用。 从业务的角度来看,该解决方案将使健身教练不仅可以管理他们的客户,锻炼和会议,而且可以成为其业务所有方面的单一参考点,而且每月费用低。

With the scaling options available in the Heroku ecosystem, the application and database could scale as needed. The income from the subscribers would fund the additional Heroku costs, keeping my personal investment costs low. More importantly, the ease-of-use with Heroku will allow me to continue building the features noted in the feature chart above and not get bogged down with infrastructure knowledge and decisions.

通过Heroku生态系统中可用的缩放选项,应用程序和数据库可以根据需要进行缩放。 来自订户的收入将为Heroku的额外费用提供资金,从而使我的个人投资成本保持较低水平。 更重要的是,Heroku的易用性使我能够继续构建上面的功能表中指出的功能,而不会陷入基础架构知识和决策的泥潭。

How do I plan to market this solution? Not really sure … too excited to start putting my ideas in place.

我打算如何推销该解决方案? 不太确定……太激动了,无法开始将我的想法付诸实践。

However, with this new design concept, I needed to figure out how to do three things:

但是,通过这个新的设计概念,我需要弄清楚如何做三件事:

  1. design a multi-tenant application that acts like a single application

    设计一个多租户应用程序,其行为类似于单个应用程序
  2. understand how security would work and be different than a single application

    了解安全性将如何工作,并且与单个应用程序不同
  3. secure and protect the data, even when a crafty developer attempts to access the API

    保护和保护数据,即使狡猾的开发人员尝试访问API

设计多租户应用程序 (Designing a Multi-Tenant Application)

According to Wikipedia, Multitenancy “refers to a software architecture in which a single instance of software runs on a server and serves multiple tenants.” In this case, I am in the process of creating a single instance of software that will serve multiple fitness trainers. As a result, the cost for each fitness trainer to use the system will be far less than if these same individuals were creating and hosting their own solution.

根据Wikipedia的说法, Multitenancy “是指一种软件体系结构,其中一个软件的单个实例在服务器上运行并为多个租户提供服务。” 在这种情况下,我正在创建一个软件实例,该实例将为多个健身教练提供服务。 结果,每个健身教练使用该系统的成本将远低于这些人创建和托管自己的解决方案的成本。

With the lessons learned from a year-long journey using AWS and the conversion effort from AWS to Heroku, my research was leading me to utilize Heroku for this application. I knew that multi-tenancy is not a challenge for Heroku, and their developer-focused approach was perfect for my situation. After all, I still work a full-time job and have a toddler in the home.

从使用AWS长达一年的旅程中汲取的经验教训以及从AWS到Heroku的转换工作,我的研究使我将Heroku用于此应用程序。 我知道对于Heroku来说,多租户并不是一个挑战,而以开发人员为中心的方法非常适合我的情况。 毕竟,我仍然是全职工作,并且在家中有个小孩。

Given my experience with Java/Spring Boot and Angular, I decided to stick with technologies I know and respect. From a database perspective, MySQL seems to be a good fit for this application, too, which will employ the ClearDB option when running in Heroku.

鉴于我在Java / Spring Boot和Angular方面的经验,我决定坚持使用我所了解和尊重的技术。 从数据库角度来看,MySQL似乎也非常适合此应用程序,当在Heroku中运行时,它将使用ClearDB选项。

In order to employ a multi-tenant design, the data (clients, workouts, sessions, etc.) for each tenant (fitness trainer) needs to be protected from other tenants. At a high level, a Tenant object was created and include a Tenant Properties object, which would provide attributes about the tenant and link to a Features object (where certain functionality could be enabled/disabled).

为了采用多租户设计,需要保护每个租户(健身教练)的数据(客户,锻炼,课程等)免受其他租户的侵害。 在较高的级别上,创建了一个Tenant对象,并包含一个Tenant Properties对象,该对象将提供有关该租户的属性并链接到Features对象(可以启用/禁用某些功能)。

Image for post

From an entity perspective, all of the objects created for the application would include a tenantId reference to the Tenant object. Since I am using Spring Boot as the RESTful API, below is an example of what the Client object looks like:

从实体的角度来看,为应用程序创建的所有对象都将包括对Tenant对象的tenantId引用。 由于我将Spring Boot用作RESTful API,因此以下是Client对象的示例:

@AllArgsConstructor@NoArgsConstructor@Data@Entity@Table(name = “clients”)public class Client {  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private long id;
@OneToOne private Tenant tenant; private boolean active;
@OneToOne private Person person;
@OneToOne private Address address;}

Using this same pattern, the remaining entities were created for the initial release:

使用相同的模式,为初始发行版创建了其余实体:

Image for post

Knowing the Spring JPA has the ability to create the necessary SQL for the database layer, I decided to give this option a try. Even though I am using application.yml for my properties file, I went ahead and dropped the following application.properties file in my resources folder:

知道Spring JPA能够为数据库层创建必要SQL之后,我决定尝试一下该选项。 即使我为属性文件使用application.yml ,我仍然将以下application.properties文件拖放到资源文件夹中:

spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=fitness.sql
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-source=metadata

Next, I started the Spring Boot service and was able to see a fully populated Data Definition Language (DDL) script for the fitness database in a file called fitness.sql.

接下来,我启动了Spring Boot服务,并能够在名为fitness.sql的文件中看到用于健身数据库的完全填充的数据定义语言(DDL)脚本。

Using Docker, Docker Compose, and the MySQL base image, I was quickly able to get the database up and running within a few minutes. As noted above, I plan to use ClearDB in Heroku, but I am not quite ready for that step. For those not wanting to utilize Docker or even run the database locally, it is possible to create a database instance in Heroku, then use an .env file to attach to the remote instance.

使用Docker,Docker Compose和MySQL基础映像,我很快就能在几分钟之内启动并运行数据库。 如上所述,我计划在Heroku中使用ClearDB,但是我还没有为这一步做好准备。 对于那些不想使用Docker甚至不想在本地运行数据库的用户,可以在Heroku中创建数据库实例,然后使用.env文件附加到远程实例。

Thereafter, I deleted the application.properties file and shut my RESTful API back down, for now.

此后,我暂时删除了application.properties文件并关闭了我的RESTful API。

选择安全提供者 (Selecting a Security Provider)

I have been quite impressed with the service offerings provided by Okta for the last five years. Across multiple projects, I have yet to find a scenario where the Okta toolset fails to meet the needs of the project. However, in this case, I had an end-state of Heroku for my multi-tenant application. So, I wanted to utilize the security partner they recommended.

Okta在过去五年中提供的服务给我留下了深刻的印象。 在多个项目中,我还没有找到Okta工具集无法满足项目需求的情况。 但是,在这种情况下,我的多租户应用程序的状态为Heroku。 因此,我想利用他们推荐的安全合作伙伴。

To my surprise, Heroku actually has partnered with Okta for application security. In fact, adding Okta to your Heroku application is as simple as the following CLI command:

令我惊讶的是,Heroku实际上已经与Okta合作来确保应用程序安全。 实际上,将Okta添加到Heroku应用程序就像以下CLI命令一样简单:

heroku addons:create okta

While this functionality is in Beta, it does automatically create all the necessary items required to allow your Heroku application to integrate with Okta. Click here for more information.

在Beta中使用此功能时,它将自动创建使Heroku应用程序与Okta集成所需的所有必要项目。 单击此处了解更多信息

安全拦截器 (Security Interceptor)

To protect one tenant from another, I wanted to introduce a SecurityInterceptor to enforce security for each request. This way, if a crafty user attempted to change an object key during the HTTP request, the interceptor would throw an error. As a result, all non-anonymous requests pass through the following class:

为了保护一个租户免受另一个租户的侵害,我想引入一个SecurityInterceptor来为每个请求强制执行安全性。 这样,如果狡猾的用户试图在HTTP请求期间更改对象密钥,则拦截器将引发错误。 结果,所有非匿名请求都通过以下类:

public class SecurityInterceptor extends HandlerInterceptorAdapter {  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {    if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().getName() != null) {      try {        // Perform the necessary logic
processRequest(SecurityContextHolder.getContext().getAuthentication().getName()); return true; } catch (FitnessException e) { log.error(“Error code={}, message={}”, e.getCode(), e.getMessage(), e); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } } log.error(“Could not determine requester information”); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; }}

The processRequest() method will pull the necessary information out of the authentication.name attribute (from the authenticated Okta user) and attempt to retrieve the Tenant record for the request.

processRequest()方法将(从经过身份验证的Okta用户中)从authentication.name属性中提取必要的信息,并尝试检索该请求的租户记录。

If the request is not successful, a FitnessException is thrown, leading to a 401 (Unauthorized) error back to the requester. However, if the request is successful, the interceptor code will create/place the following object on the request for future use:

如果请求不成功,则会抛出FitnessException,从而将401(未经授权)错误返回给请求者。 但是,如果请求成功,则拦截器代码将在请求上创建/放置以下对象以供将来使用:

@AllArgsConstructor@NoArgsConstructor@Datapublic class UserData {private Tenant tenant;private Person person;}

Now, within the request lifecycle, references to the Tenant/Person (which is the user of the application) will be used in all HTTP requests instead of the values being provided with the request.

现在,在请求生命周期内,将在所有HTTP请求中使用对Tenant / Person(应用程序的用户)的引用,而不是随请求提供的值。

展望未来 (Looking Ahead)

To summarize, at this point the following design has been put into place:

总而言之,目前已完成以下设计:

  • Initial design has been finalized

    初步设计已完成
  • Tentative release schedule has been identified

    确定了暂定的发布时间表
  • Multi-tenant design has been validated

    多租户设计已通过验证
  • Security provided has been chosen and identified

    已选择并确定提供的安全性

In the next article, I am going to focus on getting the multi-tenant client and servers up and running for the 1.0.0 release, which will include the following architecture and design:

在下一篇文章中,我将重点介绍如何为1.0.0版启动并运行多租户客户端和服务器,其中将包括以下体系结构和设计:

  • Angular 9.1.11 (browser client)

    Angular 9.1.11(浏览器客户端)
  • Spring Boot 2.3.1 (RESTful API)

    Spring Boot 2.3.1(RESTful API)
  • ClearDB/MySQL (Database)

    ClearDB / MySQL(数据库)
  • Okta (security)

    Okta(安全性)
  • GitLab (source control and CI/CD)

    GitLab(源代码控制和CI / CD)
  • Heroku (application hosting)

    Heroku(应用程序托管)

Have a really great day!

祝您有美好的一天!

翻译自: https://levelup.gitconnected.com/using-heroku-to-quickly-build-a-multi-tenant-saas-startup-part-1-9f0da344a7a4

heroku

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值