Added database, orm, auth modules

added db migrations for users and initial data
added first controllers
added auth middleware
added rest routes and controller stub
...
This commit is contained in:
Sockenklaus
2023-07-03 16:24:19 +02:00
parent f58c0c3245
commit a52c0143df
21 changed files with 459 additions and 12 deletions

View File

@@ -31,7 +31,8 @@
"@adonisjs/view",
"@adonisjs/shield",
"@eidellev/inertia-adonisjs",
"@adonisjs/lucid"
"@adonisjs/lucid",
"@adonisjs/auth"
],
"metaFiles": [
{

3
.gitignore vendored
View File

@@ -129,4 +129,5 @@ dist
.yarn/install-state.gz
.pnp.*
config/database.ts
config/database.ts
tmp

View File

@@ -0,0 +1,3 @@
// import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class AuthController {}

View File

@@ -0,0 +1,17 @@
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class EventsController {
public async index({}: HttpContextContract) {}
public async create({}: HttpContextContract) {}
public async store({}: HttpContextContract) {}
public async show({}: HttpContextContract) {}
public async edit({}: HttpContextContract) {}
public async update({}: HttpContextContract) {}
public async destroy({}: HttpContextContract) {}
}

View File

@@ -0,0 +1,9 @@
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class HomeController {
public async index({ inertia }: HttpContextContract) {
return inertia.render('Home')
}
}

View File

@@ -0,0 +1,17 @@
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UsersController {
public async index({}: HttpContextContract) {}
public async create({}: HttpContextContract) {}
public async store({}: HttpContextContract) {}
public async show({}: HttpContextContract) {}
public async edit({}: HttpContextContract) {}
public async update({}: HttpContextContract) {}
public async destroy({}: HttpContextContract) {}
}

76
app/Middleware/Auth.ts Normal file
View File

@@ -0,0 +1,76 @@
import { AuthenticationException } from '@adonisjs/auth/build/standalone'
import type { GuardsList } from '@ioc:Adonis/Addons/Auth'
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
/**
* Auth middleware is meant to restrict un-authenticated access to a given route
* or a group of routes.
*
* You must register this middleware inside `start/kernel.ts` file under the list
* of named middleware.
*/
export default class AuthMiddleware {
/**
* The URL to redirect to when request is Unauthorized
*/
protected redirectTo = '/login'
/**
* Authenticates the current HTTP request against a custom set of defined
* guards.
*
* The authentication loop stops as soon as the user is authenticated using any
* of the mentioned guards and that guard will be used by the rest of the code
* during the current request.
*/
protected async authenticate(auth: HttpContextContract['auth'], guards: (keyof GuardsList)[]) {
/**
* Hold reference to the guard last attempted within the for loop. We pass
* the reference of the guard to the "AuthenticationException", so that
* it can decide the correct response behavior based upon the guard
* driver
*/
let guardLastAttempted: string | undefined
for (let guard of guards) {
guardLastAttempted = guard
if (await auth.use(guard).check()) {
/**
* Instruct auth to use the given guard as the default guard for
* the rest of the request, since the user authenticated
* succeeded here
*/
auth.defaultGuard = guard
return true
}
}
/**
* Unable to authenticate using any guard
*/
throw new AuthenticationException(
'Unauthorized access',
'E_UNAUTHORIZED_ACCESS',
guardLastAttempted,
this.redirectTo,
)
}
/**
* Handle request
*/
public async handle (
{ auth }: HttpContextContract,
next: () => Promise<void>,
customGuards: (keyof GuardsList)[]
) {
/**
* Uses the user defined guards or the default guard mentioned in
* the config file
*/
const guards = customGuards.length ? customGuards : [auth.name]
await this.authenticate(auth, guards)
await next()
}
}

View File

@@ -0,0 +1,21 @@
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
/**
* Silent auth middleware can be used as a global middleware to silent check
* if the user is logged-in or not.
*
* The request continues as usual, even when the user is not logged-in.
*/
export default class SilentAuthMiddleware {
/**
* Handle request
*/
public async handle({ auth }: HttpContextContract, next: () => Promise<void>) {
/**
* Check if user is logged-in or not. If yes, then `ctx.auth.user` will be
* set to the instance of the currently logged in user.
*/
await auth.check()
await next()
}
}

33
app/Models/User.ts Normal file
View File

@@ -0,0 +1,33 @@
import { DateTime } from 'luxon'
import Hash from '@ioc:Adonis/Core/Hash'
import { column, beforeSave, BaseModel } from '@ioc:Adonis/Lucid/Orm'
export default class User extends BaseModel {
@column({ isPrimary: true })
public id: number
@column()
public username: string
@column({ serializeAs: null })
public password: string
@column()
public isAdmin: boolean
@column()
public rememberMeToken: string | null
@column.dateTime({ autoCreate: true })
public createdAt: DateTime
@column.dateTime({ autoCreate: true, autoUpdate: true })
public updatedAt: DateTime
@beforeSave()
public static async hashPassword (user: User) {
if (user.$dirty.password) {
user.password = await Hash.make(user.password)
}
}
}

86
config/auth.ts Normal file
View File

@@ -0,0 +1,86 @@
/**
* Config source: https://git.io/JY0mp
*
* Feel free to let us know via PR, if you find something broken in this config
* file.
*/
import type { AuthConfig } from '@ioc:Adonis/Addons/Auth'
/*
|--------------------------------------------------------------------------
| Authentication Mapping
|--------------------------------------------------------------------------
|
| List of available authentication mapping. You must first define them
| inside the `contracts/auth.ts` file before mentioning them here.
|
*/
const authConfig: AuthConfig = {
guard: 'web',
guards: {
/*
|--------------------------------------------------------------------------
| Web Guard
|--------------------------------------------------------------------------
|
| Web guard uses classic old school sessions for authenticating users.
| If you are building a standard web application, it is recommended to
| use web guard with session driver
|
*/
web: {
driver: 'session',
provider: {
/*
|--------------------------------------------------------------------------
| Driver
|--------------------------------------------------------------------------
|
| Name of the driver
|
*/
driver: 'lucid',
/*
|--------------------------------------------------------------------------
| Identifier key
|--------------------------------------------------------------------------
|
| The identifier key is the unique key on the model. In most cases specifying
| the primary key is the right choice.
|
*/
identifierKey: 'id',
/*
|--------------------------------------------------------------------------
| Uids
|--------------------------------------------------------------------------
|
| Uids are used to search a user against one of the mentioned columns. During
| login, the auth module will search the user mentioned value against one
| of the mentioned columns to find their user record.
|
*/
uids: ['username'],
/*
|--------------------------------------------------------------------------
| Model
|--------------------------------------------------------------------------
|
| The model to use for fetching or finding users. The model is imported
| lazily since the config files are read way earlier in the lifecycle
| of booting the app and the models may not be in a usable state at
| that time.
|
*/
model: () => import('App/Models/User'),
},
},
},
}
export default authConfig

73
contracts/auth.ts Normal file
View File

@@ -0,0 +1,73 @@
/**
* Contract source: https://git.io/JOdz5
*
* Feel free to let us know via PR, if you find something broken in this
* file.
*/
import User from 'App/Models/User'
declare module '@ioc:Adonis/Addons/Auth' {
/*
|--------------------------------------------------------------------------
| Providers
|--------------------------------------------------------------------------
|
| The providers are used to fetch users. The Auth module comes pre-bundled
| with two providers that are `Lucid` and `Database`. Both uses database
| to fetch user details.
|
| You can also create and register your own custom providers.
|
*/
interface ProvidersList {
/*
|--------------------------------------------------------------------------
| User Provider
|--------------------------------------------------------------------------
|
| The following provider uses Lucid models as a driver for fetching user
| details from the database for authentication.
|
| You can create multiple providers using the same underlying driver with
| different Lucid models.
|
*/
user: {
implementation: LucidProviderContract<typeof User>
config: LucidProviderConfig<typeof User>
}
}
/*
|--------------------------------------------------------------------------
| Guards
|--------------------------------------------------------------------------
|
| The guards are used for authenticating users using different drivers.
| The auth module comes with 3 different guards.
|
| - SessionGuardContract
| - BasicAuthGuardContract
| - OATGuardContract ( Opaque access token )
|
| Every guard needs a provider for looking up users from the database.
|
*/
interface GuardsList {
/*
|--------------------------------------------------------------------------
| Web Guard
|--------------------------------------------------------------------------
|
| The web guard uses sessions for maintaining user login state. It uses
| the `user` provider for fetching user details.
|
*/
web: {
implementation: SessionGuardContract<'user', 'web'>
config: SessionGuardConfig<'user'>
client: SessionClientContract<'user'>
}
}
}

View File

@@ -0,0 +1,25 @@
import BaseSchema from '@ioc:Adonis/Lucid/Schema'
export default class extends BaseSchema {
protected tableName = 'users'
public async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').primary()
table.string('username', 255).notNullable().unique()
table.string('password', 180).notNullable()
table.string('remember_me_token').nullable()
table.boolean('is_admin').notNullable().defaultTo(false)
/**
* Uses timestampz for PostgreSQL and DATETIME2 for MSSQL
*/
table.timestamp('created_at', { useTz: true }).notNullable()
table.timestamp('updated_at', { useTz: true }).notNullable()
})
}
public async down() {
this.schema.dropTable(this.tableName)
}
}

18
database/seeders/User.ts Normal file
View File

@@ -0,0 +1,18 @@
import BaseSeeder from '@ioc:Adonis/Lucid/Seeder'
import User from 'App/Models/User'
export default class extends BaseSeeder {
public async run () {
await User.createMany([
{
username: 'admin',
password: 'initialPass',
isAdmin: true
},
{
username: "firstUser",
password: "firstPass",
}
])
}
}

63
package-lock.json generated
View File

@@ -8,6 +8,7 @@
"name": "enzos-events",
"version": "1.0.0",
"dependencies": {
"@adonisjs/auth": "^8.2.3",
"@adonisjs/core": "^5.9.0",
"@adonisjs/lucid": "^18.4.0",
"@adonisjs/repl": "^3.1.11",
@@ -147,6 +148,50 @@
"@adonisjs/core": "^5.1.0"
}
},
"node_modules/@adonisjs/auth": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@adonisjs/auth/-/auth-8.2.3.tgz",
"integrity": "sha512-js9e8AHEsNC/8MGvho6MgL+uXr8SlhTg9MJJDWQBBiqsKkT7+H7NMP/pLbuSzYaaf40t2u/OXfq6wXuIC5ZYvw==",
"dependencies": {
"@poppinss/hooks": "^5.0.3",
"@poppinss/utils": "^5.0.0",
"luxon": "^3.0.4"
},
"peerDependencies": {
"@adonisjs/core": "^5.7.1",
"@adonisjs/i18n": "^1.5.0",
"@adonisjs/lucid": "^18.0.0",
"@adonisjs/redis": "^7.2.0",
"@adonisjs/session": "^6.2.0"
},
"peerDependenciesMeta": {
"@adonisjs/i18n": {
"optional": true
},
"@adonisjs/lucid": {
"optional": true
},
"@adonisjs/redis": {
"optional": true
},
"@adonisjs/session": {
"optional": true
}
}
},
"node_modules/@adonisjs/auth/node_modules/@poppinss/hooks": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@poppinss/hooks/-/hooks-5.0.3.tgz",
"integrity": "sha512-M5a151VUl+RslVP5qwDW+u+0VmzKt5Nfplzdx2nrtXol3yVlLN3u2Jp6UADESid3DDI7IRHmFrA3sQusey3eUA==",
"peerDependencies": {
"@adonisjs/application": ">=4.0.0"
},
"peerDependenciesMeta": {
"@adonisjs/application": {
"optional": true
}
}
},
"node_modules/@adonisjs/bodyparser": {
"version": "8.1.8",
"resolved": "https://registry.npmjs.org/@adonisjs/bodyparser/-/bodyparser-8.1.8.tgz",
@@ -16834,6 +16879,24 @@
"slash": "^3.0.0"
}
},
"@adonisjs/auth": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@adonisjs/auth/-/auth-8.2.3.tgz",
"integrity": "sha512-js9e8AHEsNC/8MGvho6MgL+uXr8SlhTg9MJJDWQBBiqsKkT7+H7NMP/pLbuSzYaaf40t2u/OXfq6wXuIC5ZYvw==",
"requires": {
"@poppinss/hooks": "^5.0.3",
"@poppinss/utils": "^5.0.0",
"luxon": "^3.0.4"
},
"dependencies": {
"@poppinss/hooks": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@poppinss/hooks/-/hooks-5.0.3.tgz",
"integrity": "sha512-M5a151VUl+RslVP5qwDW+u+0VmzKt5Nfplzdx2nrtXol3yVlLN3u2Jp6UADESid3DDI7IRHmFrA3sQusey3eUA==",
"requires": {}
}
}
},
"@adonisjs/bodyparser": {
"version": "8.1.8",
"resolved": "https://registry.npmjs.org/@adonisjs/bodyparser/-/bodyparser-8.1.8.tgz",

View File

@@ -66,6 +66,7 @@
"youch-terminal": "^2.2.1"
},
"dependencies": {
"@adonisjs/auth": "^8.2.3",
"@adonisjs/core": "^5.9.0",
"@adonisjs/lucid": "^18.4.0",
"@adonisjs/repl": "^3.1.11",

View File

@@ -1,5 +1,7 @@
<template>
{{ test }}
<div>
Willkommen auf der Hauptseite
</div>
</template>
<script setup>

View File

@@ -41,4 +41,6 @@ Server.middleware.register([
| Route.get('dashboard', 'UserController.dashboard').middleware('auth')
|
*/
Server.middleware.registerNamed({})
Server.middleware.registerNamed({
auth: () => import('App/Middleware/Auth')
})

View File

@@ -20,18 +20,16 @@
import Route from '@ioc:Adonis/Core/Route'
Route.get('/', async ({ inertia }) => {
return inertia.render('Home')
})
Route.get('/', 'HomeController.index')
Route.get('/login', async({inertia}) =>{
return inertia.render('Login')
})
Route.get('/events', async({ inertia }) => {
return inertia.render('Events/EventsList')
Route.resource('users', 'UsersController').middleware({
"*": ['auth']
})
Route.get('/users', async({inertia}) => {
return inertia.render('Users/UsersList')
Route.resource('events', 'EventsController').middleware({
"*": ['auth']
})

View File

@@ -34,7 +34,8 @@
"@adonisjs/shield",
"@japa/preset-adonis/build/adonis-typings",
"@eidellev/inertia-adonisjs",
"@adonisjs/lucid"
"@adonisjs/lucid",
"@adonisjs/auth"
]
}
}