• Stars
    star
    192
  • Rank 201,529 (Top 4 %)
  • Language
    Ruby
  • Created over 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rails starter kit that every startup needs

CircleCI All Contributors

Rails-pangu

δΈ­ζ–‡ζ–‡ζ‘£ Chinese document

Rails-pangu is a Rails 6(API Only) boilerplate which follows cutting-edge solutions already adopted by the industry, notablly, Devise, JWT(JSON Web Tokens), Postgres, Redis, Docker, Rspec, RuboCop, CircleCI. It is a solid production-ready starting point for your new backend projects.

Devise is a flexible and almost a standard authentication solution for Rails, while JWT(JSON Web Tokens) is a JSON-based open standard (RFC 7519) for creating access tokens, which is a distributed and faster solution than authentication through databases.

There is always a strong need to bring these two beautiful solutions together into rails for better user authentication, however, there's no single satisfying article or project which demonstrates how to incorporate both with Rails 6(API Only), which becomes the main reason for the birth of Rails-pangu.

Pangu is the first living being and the creator of all in some versions of Chinese mythology1. Just like pangu, Rails-pangu aims to be a starter kit of your next rails project which eliminates tricky but repeated work.

Getting Started

~ $ git clone https://github.com/ruilisi/rails-pangu
~ $ cd rails-pangu
~ $ bundle install
~ $ rails db:create db:migrate db:seed
~ $ rspec

Try Run & Test to get hands-on experience with rails-pangu.

Features

πŸš€ Rails 6 (API only)

As explained above, rails 6 is the future and is far different from rails 5.

πŸš€ Devise

Quoted from it's homepage:

Devise is a flexible authentication solution for Rails based on Warden. It:

  • Is Rack based;
  • Is a complete MVC solution based on Rails engines;
  • Allows you to have multiple models signed in at the same time;
  • Is based on a modularity concept: use only what you really need.

To our best of knowledge, devise provides a full, industry-standard, easy-to-ingrate way of all kinds of authentication. Damn, it's awesome!

πŸš€ JWT

JSON Web Tokens

πŸš€ devise-jwt

While there are lots of solutions which hook devise and jwt together, this repo is better implemented from our point of view.

We implmented a devise-jwt denylist policy leveraging the power of redis in app/models/jwt_denylist.rb.

πŸš€ Postgres

We use postgres as default database store cause sqlite3 will be replaced sooner or later when the traffic of one web server becomes lager enough

πŸš€ Rspec

Behaviour Driven Development for Ruby. Making TDD Productive and Fun.

πŸš€ RuboCop

A Ruby static code analyzer and formatter, based on the community Ruby style guide. https://docs.rubocop.org

πŸš€ CircleCI

CircleCI is the leading continuous integration and delivery platform for teams looking to shorten the distance between idea and delivery In this project, we leverage CircleCI to test Rails-pangu's code base with both rspec and RuboCop

πŸš€ Factory Bot

A library for setting up Ruby objects as test data.

πŸš€ Docker

Dockerfile with customized features is added to this project:

  • Original gem source https://rubygems.org is mirrored to https://gems.ruby-china.com which both accelerates bundling speed for developers in China and acts as an example of using Gem mirror.

πŸš€ Docker Compose

docker-compose.yml with containers web, postgres, redis is added.

rspec and some other commands are not avaiable in web container since the docker image is bundled with only gems for production mode through bundle config set without 'development test'.

~ $ docker-compose up -d
~ $ docker-compose exec web rails db:create db:migrate db:seed

Then you can run steps in Run & Test as port 3000 is mapped and exposed.

πŸš€ Puma

Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications in development and production.

πŸš€ Redis

Is there any web project isn't using redis as a faster and sometimes easier way of storing data? Well, if there isn't, just replace it!

CORS

config/cors.rb is changed in the way that any origin is allowed, and Authorization is allowed in header of any kind of request.

Cronjobs

We provide several ways with convenient defaults for adding cronjobs into the running containers as cronjobs are a big part for a project.

puts [
  "59 * * * * ruby script",
  "*/10 * * * * ruby script"
].map { |job|
  *schedule, cmd = job.split(' ')
  "#{schedule.join(' ')} cd /usr/src/app; rails runner \"Util.run_once('#{cmd}')\""
}.join("\n")

If you want to run bash script, you can replace cd /usr/src/app; rails runner \"Util.run_once('#{cmd}')\" to your custom cmd.

Create a role

In addition to the default role we provide, we also allow developers to create their custom role. There is a document about how to create a new role

Denylist

Default denylist with redis

Redis is a good option for denylist that will allow fast in memory access to the list. In jwt_denylist record, we implement denylist with redis. By setting redis expiration time to be the same as jwt token expiration time, this token can be automatically deleted from redis when the token expires.

  def self.jwt_revoked?(payload, user)
    # Check if in the denylist
    $redis.get("user_denylist:#{user.id}:#{payload['jti']}").present?
  end

  def self.revoke_jwt(payload, user)
    # REVOKE JWT
    expiration = payload['exp'] - payload['iat']
    $redis.setex("user_denylist:#{user.id}:#{payload['jti']}", expiration, payload['jti'])
  end

Custom denylist

You can also implement denylist by your own strategies. You just need to rewrite two methods: jwt_revoked? and revoke_jwt in jwt_denylist.rb, both of them accepting as parameters the JWT payload and the user record, in this order.

  def self.jwt_revoked?(payload, user)
    # Does something to check whether the JWT token is revoked for given user
  end

  def self.revoke_jwt(payload, user)
    # Does something to revoke the JWT token for given user
  end

Dispatch requests

You can config dispatch_requests in devise.rb. When config it, you need to tell which requests will dispatch tokens for the user that has been previously authenticated (usually through some other warden strategy, such as one requiring username and email parameters). To configure it, you can add the the request path to dispath_requests.

  jwt.dispatch_requests = [['POST', %r{^users/sign_in$}]]

Revocation requests

You can config dispatch_requests in devise.rb. When config it, you need to tell which requests will revoke incoming JWT tokens, and you can add the the request path to revocation_requests

  jwt.revocation_requests = [['DELETE', %r{^users/sign_out$}]]

Jwt payload

user records may also implement a jwt_payload method, which gives it a chance to add something to the JWT payload.

  def jwt_payloads
    # { 'foo' => 'bar' }
  end

Jwt dispatch

You can add a hook method on_jwt_dispatch on the user record. It will execute when a token dispatched for that user instance, and it takes token and payload as parameters. And this method will call when you access the routes which in dispatch_requests

  def on_jwt_dispatch(token, payload)
    # do_something(token, payload)
  end

Run & Test

Requirements

  • Rails server running with rails s
  • httpie installed
~ $ http -b localhost:3000/ping
pong

~ $ http -b post localhost:3000/users user:='{"email":"[email protected]","password":"Test1aBc"}'
{
    "created_at": "2020-10-10T05:43:20.349Z",
    "email": "[email protected]",
    "id": 1,
    "updated_at": "2020-10-10T05:43:20.349Z"
}

~ $ http post localhost:3000/users/sign_in user:='{"email":"[email protected]","password":"Test1aBc"}'
HTTP/1.1 200 OK
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwic2NwIjoidXNlciIsImF1ZCI6bnVsbCwiaWF0IjoxNjAyMzE3ODYxLCJleHAiOjE2MDI0MDQyNjEsImp0aSI6IjNkOGY4ZThkLTY2YjUtNGE5Ny05YzkzLTUxZmFmMGQyMTM1YSJ9.Q-HWFNtLtfNO2iZsTRBfmlJlBBxHWTwrSlTjBaS6GNI
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
ETag: W/"df30d418ad05c15dbfdc6e34ef53f723"
Referrer-Policy: strict-origin-when-cross-origin
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 957a1c92-c5a8-4607-81df-6ca70ba9b846
X-Runtime: 0.193702
X-XSS-Protection: 1; mode=block

{
    "created_at": "2020-10-10T05:43:20.349Z",
    "email": "[email protected]",
    "id": 1,
    "updated_at": "2020-10-10T05:43:20.349Z"
}

GET auth_ping with the bearer(eyJhbGciOiJIUzI1NiJ9...) returned by POST users/sign_in:

~ $ http -b localhost:3000/auth_ping "Authorization:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwic2NwIjoidXNlciIsImF1ZCI6bnVsbCwiaWF0IjoxNjAyMzE3ODYxLCJleHAiOjE2MDI0MDQyNjEsImp0aSI6IjNkOGY4ZThkLTY2YjUtNGE5Ny05YzkzLTUxZmFmMGQyMTM1YSJ9.Q-HWFNtLtfNO2iZsTRBfmlJlBBxHWTwrSlTjBaS6GNI"
pong

GET auth_ping without bearer will result 401 Unauthorized:

~ $ http localhost:3000/auth_ping                                                                                                                                                              [ruby-2.7.2]
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Content-Type: */*; charset=utf-8
Transfer-Encoding: chunked
X-Request-Id: 8c21f5f2-f385-4b0b-b1f6-478ef06de256
X-Runtime: 0.003266

You need to sign in or sign up before continuing.

Projects using rails-pangu

  • LINGTI (https://lingti666.com/): Lingti is a game booster which brings faster, smoother gaming experience with clients of PC/Mac/Android/iOS/Router/Router Plugin implemented.
  • eSheep (https://esheeps.com/): Network booster which helps global users access better entertainment content from Asia.

License

Code and documentation copyright 2019 the Rails-pangu Authors and Ruilisi Technology Code released under the MIT License.

Contributors ✨

Thanks goes to these wonderful people (emoji key):

hophacker
hophacker

πŸ’» πŸ“– πŸš‡
Jiawei Li
Jiawei Li

πŸ’» πŸ“–
tato
tato

πŸ’» πŸ“–
caibiwsq
caibiwsq

πŸ’» πŸ“–
Eric Guo
Eric Guo

πŸ’» πŸ“–

This project follows the all-contributors specification. Contributions of any kind welcome!

Reference

More Repositories

1

fortune-sheet

A drop-in javascript spreadsheet library that provides rich features like Excel and Google Sheets
TypeScript
2,384
star
2

css-checker

Reduce Similar & Duplicated CSS Classes with Diff in Seconds!
Go
577
star
3

react-chessground

React wrapper of Chessground
JavaScript
131
star
4

go-pangu

rest api web server based on go(High availability, high security, high performance)
Go
45
star
5

react-media-previewer

A media previewer component for React
TypeScript
20
star
6

NSHoverableButton

NSButton with two images for hovering and not hovering separately
Swift
19
star
7

react-keycode-input

A cool component for inputing many kinds of code
JavaScript
17
star
8

macbit

Macbit aims to solve mac development issues in a bit level.
C
11
star
9

chart-pangu

Pangu-chart is a helm chart template which inherits from the default template, but brings many conveniences originated from our daily devops.
HTML
10
star
10

rails-influxdb-logger

Logger for Influxdb in Rails
Ruby
10
star
11

NSGradientView

NSView with Gradient Background Colour Settings for Mac OS
Swift
9
star
12

feishu-api

FeishuApi is an integration of commonly used feishu open platform's APIs, easy to call.
Ruby
7
star
13

dockery

JavaScript
7
star
14

CountryCodeNSTextField

CountryCodeNSTextField subclasses NSTextfield for International Phone Calling Code Input With Flags
Swift
6
star
15

weibo-crawler

Weibo-crawler is a crawler project based on golang colly framework to crawl weibo sites and get information. It crawls web content by regular expressions and Xpath selector, spatially transforms keywords using word vector model, and clusters text content by HDBSCAN clustering algorithm.
Go
6
star
16

pangu.js

JavaScript
5
star
17

golang-crawler-example

HTML
5
star
18

learn-webpack

JavaScript
5
star
19

goetc

Go
5
star
20

Rocket.Chat.Go.SDK

Go SDK for REST API and Realtime api(almost all api)
Go
5
star
21

NSScrollSideBar

Swift
4
star
22

react-pangu

JavaScript
4
star
23

nextjs-docker-base

docker image base for nextjs
Dockerfile
4
star
24

css-cookbook

https://ruilisi.github.io/css-cookbook/
4
star
25

govet

Go
4
star
26

actioncable-jwt

Actioncable with authentication by jwt token
Ruby
3
star
27

golang-examples

Go
3
star
28

IMChatSDK-Mac

Swift
2
star
29

fortune-sheet-demo

HTML
2
star
30

UICustomView

Swift
2
star
31

IMChatSDK

Swift
2
star
32

xcode-cookbook

2
star
33

actioncable-rails

JavaScript
1
star
34

esheep

1
star
35

react-chessground-demo

JavaScript
1
star
36

rails-6-api-template

Ruby
1
star
37

rollup-react-library

Another react library creator which follows latest js libraries
JavaScript
1
star
38

chatsdk

Sample DatoCMS website built with GatsbyJS
Sass
1
star
39

fortune-sheet-docs

HTML
1
star