Një udhëzues i shpejtë për krijimin e një API të vërtetuar të dokerizuar me Koa. Kjo mund të përdoret si bazë për të krijuar çdo API që ju pëlqen, nga aplikacionet e motit deri te menaxhimi i restoranteve. Mund të lidhet lehtësisht me çdo frontend, për të krijuar një aplikacion funksional në internet. Ndërsa nuk do të shtohet shumë funksionalitet në këtë udhëzues, ai do të përfundojë të gjithë konfigurimin e nevojshëm për të nisur aplikacionin tuaj! Për pllakën e plotë të bojlerit, shikoni këtë depo GitHub: https://github.com/oflint-1/koa-auth-boilerplate.
Kushtet paraprake:
- Npm dhe nyja
- Doker
Teknologjitë e përdorura:
- KoaJS (korniza Javascript e përdorur për të krijuar API)
- Pasaporta (Ofron vërtetimin)
- MongoDB + Mongoose (Kjo do të jetë baza e të dhënave për API)
- Docker + DockerCompose (Për të lidhur pjesë të ndryshme të aplikacionit)
Duke filluar
Së pari, krijoni një dosje të re dhe inicializoni npm
mkdir koa-api && cd koa-api
npm init -y
Kjo do të krijojë një skedar bazë package.json
dhe do të konfigurojë mjedisin tuaj të nyjes.
Më pas, instaloni paketat fillestare për konfigurimin bazë të Koa.
npm i koa koa-bodyparser koa-router @koa/cors koa-session
Tani mund të fillojmë të krijojmë bazat e aplikacionit tonë. Krijo një skedar të ri të quajtur app.js
/* app.js */
// Imports
const Koa = require("koa");
const Router = require("koa-router"); // Import routing
const bodyParser = require("koa-bodyparser"); // Imports request parser
const cors = require("@koa/cors");
const session = require("koa-session"); // Import authentication sessions
// Create a new Koa app
const app = new Koa();
// Setup default configuration
app.use(cors({ credentials: true }));
app.keys = ["super-secret-key"]; // Sets application key (Make secure for production)
app.use(session(app)); // Tells app to use sessions
// Initialise request parser
app.use(bodyParser());
// Listen on port 3000
app.listen(3000);
Kjo do të krijojë infrastrukturën bazë për projektin tonë. Ekzekutoni node app.js
dhe lundroni te localhost:3000
në shfletuesin tuaj të preferuar të internetit dhe duhet të shihni që serveri juaj i uebit po funksionon. Aktualisht kjo duhet të shfaqë një mesazh Not found
pasi ne nuk kemi shtuar ende asnjë rrugë në aplikacionin tonë.
Vendosni rrugët bazë
Tani, ne duam të krijojmë rrugët tona bazë API.
Krijo një skedar routes/index.js
/* routes/index.js */
// Setup basic routes
module.exports = (router) => {
// Set prefix for all routes
router.prefix("/api");
// Include api routes
router.use("", require("./api"));
};
Kjo do të konfigurojë ruterin bazë. Tani duhet të konfigurojmë rrugët API.
Më pas, krijoni skedarin routes/api.js
.
/* routes/api.js */
// Import and create router
const Router = require("koa-router");
const router = new Router();
// GET basic route
router.get("/", (ctx, next) => {
ctx.body = "Hello Api!";
});
// Export router
module.exports = router.routes();
Kjo do të konfigurojë një rrugë fillestare dhe do ta shtojë atë në ruter.
Më pas, shtoni në app.js
pas analizuesit të trupit.
/* app.js */
...
// Add routes
const router = new Router(); // Create new router
require("./routes")(router); // Require external routes and pass in the router
app.use(router.routes()); // Use all routes
app.use(router.allowedMethods()); // Setup allowed methods
...
Tani ne mund të shohim rrugën tonë bazë në veprim! Edhe një herë, ekzekutoni nyjen app.js
dhe vizitoni localhost:3000/api/
dhe do të shihni një mesazh që thotë Hello Api!
Vendosja e bazës së të dhënave me docker
Më pas do të lidhim API-në tonë me një shërbim të bazës së të dhënave. Ne do të lidhim aplikacionin tonë dhe do ta lidhim atë me mongoDB. Për të filluar, sigurohuni që docker është instaluar dhe funksionon në sistemin tuaj. Shihni: https://docs.docker.com/engine/install/
Krijoni një skedar të ri në dosjen rrënjë të aplikacionit tuaj të quajtur dockerfile
FROM node
WORKDIR /app
COPY package.json /app
COPY package-lock.json /app
RUN npm install
RUN npm install -g nodemon
COPY . /app
EXPOSE 3000
CMD ["nodemon", "app.js"]
Kjo do të krijojë një mjedis të ri nyje, do të kopjojë mbi skedarët e paketës dhe do të instalojë paketat e kërkuara. Më pas ekspozon portin e duhur dhe ekzekuton nodemon për një server që ringarkohet kur bëhet ndonjë ndryshim.
Tani do të përdorim docker compose për të lidhur pjesë të ndryshme të API-së sonë.
Krijo një skedar docker-compose.yml
, përsëri në dosjen rrënjë:
#docker-compose.yml
version: "2.0"
# Define the services/containers to be run
services:
koa-auth-api: #name of your service
build: . # specify the directory of the Dockerfile
restart: always
ports:
- "3000:3000" #specify ports forwarding
links:
- database # link this service to the database service
volumes:
- .:/app
depends_on:
- database
database: # name of the service
image: mongo # specify image to build container from
ports:
- "27017:27017"
volumes:
- /data/db
Kjo do të krijojë bazën e të dhënave dhe kontejnerin API dhe do t'i lidhë ato së bashku. Për ta parë këtë në veprim, dilni nga aplikacioni juaj i nyjes nëse është ende duke u ekzekutuar me CTRL + C
dhe ekzekutoni docker-compose up
. Do të duhen disa momente për të instaluar dhe krijuar kontejnerët tuaj docker, por më pas duhet të jeni në gjendje ta shikoni aplikacionin njësoj si më parë.
Tani do të lidhemi me bazën e të dhënave nga API-ja jonë. Së pari, instaloni mongoose me npm i mongoose
për t'u lidhur me bazën e të dhënave Mongo.
Tani në app.js
, importoni mongoose me importet e tjera.
/* app.js */
...
const mongoose = require("mongoose"); // Imports Mongoose which is used to link to MongoDB
...
Tani duhet të lidhemi me bazën e të dhënave. Vendoseni këtë kod pak përpara se të shtojmë analizuesin e trupit në aplikacionin tonë.
/* app.js */
...
// Connect to database
mongoose.connect(`mongodb://database:27017/test`, {
useNewUrlParser: true,
useUnifiedTopology: true,
}); // Connects to database
var db = mongoose.connection; // Stores connection
db.on("error", console.error.bind(console, "connection error:")); // Logs any errors
...
Tani kemi lidhjen tonë të bazës së të dhënave, duhet të përdorim Mongoose për të krijuar një model për përdoruesin tonë. Krijo një skedar të ri models/user.js
.
/* models/user.js */
// Imports
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema(
{
// Username - must be unique and fit criteria
username: {
type: String,
required: true,
unique: true,
minlength: 1,
maxlength: 20,
},
// Password - will be hashed before storage
password: { type: String, required: true },
},
{
timestamps: true,
}
);
// Export model
module.exports = mongoose.model("User", userSchema);
Kjo krijon modelin tonë të përdoruesit, i cili do të mbajë të gjithë përdoruesit tanë në bazën e të dhënave. Kjo do të përdoret më vonë për vërtetim.
Duke folur për vërtetimin…
Vendosja e vërtetimit
Tani jemi gati të konfigurojmë vërtetimin përfundimtar. Së pari, instaloni kërkesat.
npm i bcryptjs koa-passport@4 passport-local
Shënim: Duhet të përdorim koa-passport 4 për shkak të një problemi me pasaportën 6. Shihni: https://github.com/jaredhanson/passport/issues/904.
Krijo një skedar auth.js
në dosjen e aplikacionit rrënjë për të trajtuar vërtetimin e përdoruesit.
/* auth.js */
// Imports
const passport = require("koa-passport");
const LocalStrategy = require("passport-local").Strategy; // Import strategy
const User = require("./models/user"); // Get user model
const bcrypt = require("bcryptjs"); // Used to encrypt passwords
const options = {};
// Utility functions for user serialization
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, function (err, user) {
done(err, user);
});
});
// Setup authentication
passport.use(
new LocalStrategy(options, (username, password, done) => {
// Get user from database
User.findOne({ username: username }, (err, user) => {
if (!user) return done(null, false);
// Compare passwords
if (comparePass(password, user.password)) {
return done(null, user);
} else {
return done(null, false);
}
});
})
);
// Utility function to compare passwords with hashed versions
function comparePass(userPassword, databasePassword) {
return bcrypt.compareSync(userPassword, databasePassword);
}
Kjo vendos pasaportën për të punuar me KoaJS dhe MongoDB. Ne kemi përcaktuar funksione për serializimin dhe deserializimin e përdoruesve dhe kemi vendosur strategjinë tonë të vërtetimit. Njoftim për të krahasuar fjalëkalimet këtu, ne po përdorim bcrypt për të krahasuar me versionet e hash.
Më pas duhet të konfigurojmë vërtetimin brenda aplikacionit tonë kryesor.
Së pari, importojeni atë në app.js
/* app.js */
...
const passport = require("koa-passport");
...
Më pas, konfiguroni auth-in në app.js
përpara lidhjes së bazës së të dhënave
/* app.js */
...
// Setup authentication
require("./auth"); // Fetches auth file functinos
app.use(passport.initialize()); // Intialises passport authentication
app.use(passport.session()); // Initialises passport sessions
...
Tani vërtetimi është konfiguruar, ne duhet të krijojmë rrugë për të hyrë në të.
Krijo skedarin routes/auth.js
/* routes/auth.js */
// Setup router
const Router = require("koa-router");
const router = new Router();
const Ctrl = require("../controllers/auth");
// Define routes
router.get("/", (ctx, next) => {
ctx.body = "Hello Auth!";
});
router.post("/login", Ctrl.login);
router.post("/signup", Ctrl.signup);
router.get("/status", Ctrl.status);
router.get("/logout", Ctrl.logout);
// Export router
module.exports = router.routes();
Vini re se rrugët janë të gjitha të lidhura me kontrollorët. Ne nuk i kemi krijuar ende këto, kështu që ato nuk do të funksionojnë për momentin.
Shtoni këto rrugë të reja te ruteri në api.js
përpara se të eksportoni ruterin.
/* routes/api.js */
...
// Add subroutes to main router
router.use("/auth", require("./auth"));
...
Tani do të krijojmë kontrollues të vërtetimit në mënyrë që rrugët tona të funksionojnë siç synohet. Ky është një skedar mjaft i gjatë, por do të kryejë veprimet themelore të regjistrimit, hyrjes dhe daljes
Krijo skedarin controllers/auth.js
/* controllers/auth.js */
// Imports
const User = require("../models/user");
const passport = require("koa-passport");
const bcrypt = require("bcryptjs");
// Login function
async function login(ctx) {
return passport.authenticate("local", (err, user, info, status) => {
if (user) {
ctx.login(user);
ctx.redirect("/api/auth/status");
} else {
ctx.status = 400;
ctx.body = { status: "error" };
}
})(ctx);
}
// Signup function
async function signup(ctx) {
console.log(ctx.request.body.username);
// Generate salt
const salt = bcrypt.genSaltSync();
// Generate hash using password and salt
const hash = bcrypt.hashSync(ctx.request.body.password, salt);
// Create new user document using username and hash
const newUser = new User({
username: ctx.request.body.username,
password: hash,
});
// Save user to database
const savedUser = await newUser.save().catch((err) => console.log(err));
console.log(savedUser);
// If user saved correctly, login user
if (savedUser) {
// Authenticate user
return passport.authenticate("local", (err, user, info, status) => {
// If user is valid
if (user) {
// Login user
ctx.login(user);
ctx.redirect("/api/auth/status");
} else {
// Return error
ctx.status = 400;
ctx.body = { status: "error" };
}
})(ctx);
} else {
// If no user returned, return a bad request
ctx.status = 400;
}
}
// Status function
async function status(ctx) {
// Check whether user is authenticated
if (ctx.isAuthenticated()) {
ctx.body = true;
} else {
ctx.body = false;
}
}
// Logout function
async function logout(ctx) {
if (ctx.isAuthenticated()) {
// Logout user
ctx.logout();
ctx.status = 200;
ctx.body = "logged out";
} else {
// Throw error
ctx.body = { success: false };
ctx.throw(401);
}
}
// Export functions
module.exports = {
login,
signup,
status,
logout,
};
Me funksionimin e të gjithë këtyre kontrollorëve, aplikacioni ynë është i plotë! Shikoni URL-të kryesore më poshtë dhe seksionin "Përpara" për të parë se si mund të përdoret kjo.
URL-të kryesore
/api/auth/login
- Identifikohu një përdorues. Dërgo emrin e përdoruesit dhe fjalëkalimin duke përdorur JSON në trupin e kërkesës.
/api/auth/signup
- Regjistro një përdorues. Dërgo emrin e përdoruesit dhe fjalëkalimin duke përdorur JSON në trupin e kërkesës.
/api/auth/status
- Merrni informacion nëse jeni aktualisht i identifikuar.
/api/auth/logout
- Dil nga përdoruesi aktual.
/api/
- Rruga bazë për API
Formati i kërkesës
Shumica e kërkesave për pikat fundore të mësipërme duhet të ndjekin formatin e mëposhtëm:
{
"username": "example_username",
"password": "example_password"
}
Duke ecur perpara
Për ta provuar atë, drejtohuni në linjën tuaj të komandës dhe ekzekutoni docker-compose up
. Me çdo fat, aplikacioni juaj duhet të funksionojë. Për ta testuar këtë, ne mund të përdorim një mjet të tillë si postier. Thjesht bashkëngjitni informacionin e hyrjes në trupin e kërkesës si një objekt JSON dhe gjithçka duhet të funksionojë!
Nga këtu, ju mund të krijoni rrugët, modelet dhe kontrollorët tuaj. Përdorimi i këtij dizajni të modularizuar do të ndihmojë me çdo zhvillim të ardhshëm dhe çdo seksion mund të ndryshohet individualisht. Kjo mund të përdoret si bazë për çdo aplikacion të ardhshëm që kërkon një API të vërtetuar. Për pllakën e plotë të boilerplate, shikoni këtë depo GitHub: https://github.com/oflint-1/koa-auth-boilerplate
Botuar fillimisht në https://enscrybe-blog.netlify.app.