The process of implementing security authentication in Laravel 6, Module, and Lighthouse (using the validator class to support complex validation rules)
1. The structure when the request responds successfully. as shown in Figure 1
mutation {
onlineStoreThemeAssetCreate(
input: { themeId: "vogue", content: "string", key: "string" }
) {
themeAsset {
id
themeId
content
key
mimeType
category
schema
createdAt
updatedAt
deletable
renameable
updatable
}
}
}
{
"data": {
"onlineStoreThemeAssetCreate": {
"themeAsset": {
"id": "653",
"themeId": "vogue",
"content": "string",
"key": "string",
"mimeType": "text/x-php",
"category": "unknown",
"schema": null,
"createdAt": "2022-02-25 01:49:53",
"updatedAt": "2022-02-25 01:49:53",
"deletable": false,
"renameable": false,
"updatable": false
}
}
}
}
2. However, at this stage, there is no security verification for the request parameters. Reference:https://lighthouse-php.com/master/security/validation.html#single-arguments. Lighthouse allows you to use Laravel’s validation in queries and changes. as shown in Figure 2
3. Although the change of this GraphQL API has only 3 parameters in the input object, the verification rules are more complicated. Contains the following rules:
(1) Verify whether there is a record of ThemeID: “VOGUE” in the table, if it does not exist, the verification fails;
SELECT * FROM `object_store`.`theme_asset` WHERE `theme_id` = 'vogue' LIMIT 0,1
(2) Verify the format of “string” , which must be a valid relative path, for example: assets/iconfont/iconfont.css. Its value is equal to String , and the validation fails;
(3) Verify the format of “string” , after it is a valid relative path, its file suffix must belong to a predefined array, for example:[‘json’, ‘css’, ‘js’];
(4) Validate the themeID: “vogue”, key: “string” The uniqueness of the record, if it already exists, the verification fails;
SELECT * FROM `object_store`.`theme_asset` WHERE `theme_id` = 'vogue' AND `asset_key` = 'string' LIMIT 0,1
(5) Verify the format of “string” , for example: when the file suffix of the key value is .json , the value format of the content needs to be validated in json format;
(6) The value of mime_type needs to be converted based on the value of key;
(7) The value of the category needs to be converted based on the value of the key;
4. Use the validator class to support complex validation rules. Lighthouse uses a simple naming convention for validator classes, just use the name of the input type and append Validator . Final build file: /app/graphql/validators/createOnlineStoreEthemeAssetInputValidator.php
PS E:\wwwroot\lighthouse-tutorial> php artisan lighthouse:validator CreateOnlineStoreThemeAssetInputValidator
Validator created successfully.
5. Since you need to use this validator class in Module Themestore now, put the file: /app/graphql/validators/CreateOnlineStoreThemeAssetInputValidator.php Cut to: /modules/themestore/validators/createOnlineStoreEthemeAssetInputValidator.php
<?php
namespace Modules\ThemeStore\Validators;
use Nuwave\Lighthouse\Validation\Validator;
class CreateOnlineStoreThemeAssetInputValidator extends Validator
{
/**
* Return the validation rules.
*
* @return array<string, array<mixed>>
*/
public function rules(): array
{
return [
'themeId' => [
'exists:theme_asset,theme_id'
],
];
}
}
6. Edit the file: /modules/themestore/resources/graphql/theme_asset.graphql, modify the input object, use the @validator directive to specify the validator class
input OnlineStoreThemeAssetCreateInput @validator(class: "Modules\\ThemeStore\\Validators\\CreateOnlineStoreThemeAssetInputValidator") {
"主题ID"
themeId: String!,
"内容"
content: String!,
"路径,相对于主题的路径,如 pages/index.blade.php"
key: String!,
}
7. Test whether the rules are valid and determine whether it is valid. as shown in Figure 3
mutation {
onlineStoreThemeAssetCreate(
input: { themeId: "vogue1", content: "string", key: "string" }
) {
themeAsset {
id
themeId
content
key
mimeType
category
schema
createdAt
updatedAt
deletable
renameable
updatable
}
}
}
{
"errors": [
{
"message": "Validation failed for the field [onlineStoreThemeAssetCreate].",
"extensions": {
"validation": {
"input.themeId": [
"The selected input.theme id is invalid."
]
},
"category": "validation"
},
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"onlineStoreThemeAssetCreate"
],
"trace": [
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Schema\\Directives\\ArgTraversalDirective.php",
"line": 29,
"call": "Nuwave\\Lighthouse\\Validation\\ValidateDirective::Nuwave\\Lighthouse\\Validation\\{closure}(null, array(1), instance of Nuwave\\Lighthouse\\Schema\\Context, instance of GraphQL\\Type\\Definition\\ResolveInfo)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Schema\\Directives\\TrimDirective.php",
"line": 56,
"call": "Nuwave\\Lighthouse\\Schema\\Directives\\ArgTraversalDirective::Nuwave\\Lighthouse\\Schema\\Directives\\{closure}(null, array(1), instance of Nuwave\\Lighthouse\\Schema\\Context, instance of GraphQL\\Type\\Definition\\ResolveInfo)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Schema\\Factories\\FieldFactory.php",
"line": 99,
"call": "Nuwave\\Lighthouse\\Schema\\Directives\\TrimDirective::Nuwave\\Lighthouse\\Schema\\Directives\\{closure}(null, array(1), instance of Nuwave\\Lighthouse\\Schema\\Context, instance of GraphQL\\Type\\Definition\\ResolveInfo)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 623,
"call": "Nuwave\\Lighthouse\\Schema\\Factories\\FieldFactory::Nuwave\\Lighthouse\\Schema\\Factories\\{closure}(null, array(1), instance of Nuwave\\Lighthouse\\Schema\\Context, instance of GraphQL\\Type\\Definition\\ResolveInfo)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 550,
"call": "GraphQL\\Executor\\ReferenceExecutor::resolveFieldValueOrError(instance of GraphQL\\Type\\Definition\\FieldDefinition, instance of GraphQL\\Language\\AST\\FieldNode, instance of Closure, null, instance of GraphQL\\Type\\Definition\\ResolveInfo)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 474,
"call": "GraphQL\\Executor\\ReferenceExecutor::resolveField(GraphQLType: Mutation, null, instance of ArrayObject(1), array(1))"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 857,
"call": "GraphQL\\Executor\\ReferenceExecutor::GraphQL\\Executor\\{closure}(array(0), 'onlineStoreThemeAssetCreate')"
},
{
"call": "GraphQL\\Executor\\ReferenceExecutor::GraphQL\\Executor\\{closure}(array(0), 'onlineStoreThemeAssetCreate')"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 859,
"function": "array_reduce(array(1), instance of Closure, array(0))"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 490,
"call": "GraphQL\\Executor\\ReferenceExecutor::promiseReduce(array(1), instance of Closure, array(0))"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 263,
"call": "GraphQL\\Executor\\ReferenceExecutor::executeFieldsSerially(GraphQLType: Mutation, null, array(0), instance of ArrayObject(1))"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\ReferenceExecutor.php",
"line": 215,
"call": "GraphQL\\Executor\\ReferenceExecutor::executeOperation(instance of GraphQL\\Language\\AST\\OperationDefinitionNode, null)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\Executor\\Executor.php",
"line": 156,
"call": "GraphQL\\Executor\\ReferenceExecutor::doExecute()"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\GraphQL.php",
"line": 162,
"call": "GraphQL\\Executor\\Executor::promiseToExecute(instance of GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter, instance of GraphQL\\Type\\Schema, instance of GraphQL\\Language\\AST\\DocumentNode, null, instance of Nuwave\\Lighthouse\\Schema\\Context, array(0), null, null)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\webonyx\\graphql-php\\src\\GraphQL.php",
"line": 94,
"call": "GraphQL\\GraphQL::promiseToExecute(instance of GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter, instance of GraphQL\\Type\\Schema, instance of GraphQL\\Language\\AST\\DocumentNode, null, instance of Nuwave\\Lighthouse\\Schema\\Context, array(0), null, null, array(29))"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\GraphQL.php",
"line": 268,
"call": "GraphQL\\GraphQL::executeQuery(instance of GraphQL\\Type\\Schema, instance of GraphQL\\Language\\AST\\DocumentNode, null, instance of Nuwave\\Lighthouse\\Schema\\Context, array(0), null, null, array(29))"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\GraphQL.php",
"line": 203,
"call": "Nuwave\\Lighthouse\\GraphQL::executeParsedQuery(instance of GraphQL\\Language\\AST\\DocumentNode, instance of Nuwave\\Lighthouse\\Schema\\Context, array(0), null, null)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\GraphQL.php",
"line": 162,
"call": "Nuwave\\Lighthouse\\GraphQL::parseAndExecuteQuery('mutation {\n onlineStoreThemeAssetCreate(\n input: { themeId: \"vogue1\", content: \"string\", key: \"string\" }\n ) {\n themeAsset {\n id\n themeId\n content\n key\n mimeType\n category\n schema\n createdAt\n updatedAt\n deletable\n renameable\n updatable\n }\n }\n}', instance of Nuwave\\Lighthouse\\Schema\\Context, array(0), null, null)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\GraphQL.php",
"line": 121,
"call": "Nuwave\\Lighthouse\\GraphQL::executeOperation(instance of GraphQL\\Server\\OperationParams, instance of Nuwave\\Lighthouse\\Schema\\Context)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Support\\Utils.php",
"line": 99,
"call": "Nuwave\\Lighthouse\\GraphQL::Nuwave\\Lighthouse\\{closure}(instance of GraphQL\\Server\\OperationParams)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\GraphQL.php",
"line": 120,
"call": "Nuwave\\Lighthouse\\Support\\Utils::applyEach(instance of Closure, instance of GraphQL\\Server\\OperationParams)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Support\\Http\\Controllers\\GraphQLController.php",
"line": 32,
"call": "Nuwave\\Lighthouse\\GraphQL::executeOperationOrOperations(instance of GraphQL\\Server\\OperationParams, instance of Nuwave\\Lighthouse\\Schema\\Context)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php",
"line": 48,
"call": "Nuwave\\Lighthouse\\Support\\Http\\Controllers\\GraphQLController::__invoke(instance of Illuminate\\Http\\Request, instance of Nuwave\\Lighthouse\\GraphQL, instance of Illuminate\\Events\\Dispatcher, instance of Laragraph\\Utils\\RequestParser, instance of Nuwave\\Lighthouse\\Execution\\SingleResponse, instance of Nuwave\\Lighthouse\\Execution\\ContextFactory)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php",
"line": 219,
"call": "Illuminate\\Routing\\ControllerDispatcher::dispatch(instance of Illuminate\\Routing\\Route, instance of Nuwave\\Lighthouse\\Support\\Http\\Controllers\\GraphQLController, '__invoke')"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php",
"line": 176,
"call": "Illuminate\\Routing\\Route::runController()"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 681,
"call": "Illuminate\\Routing\\Route::run()"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 130,
"call": "Illuminate\\Routing\\Router::Illuminate\\Routing\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Support\\Http\\Middleware\\AttemptAuthentication.php",
"line": 34,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Nuwave\\Lighthouse\\Support\\Http\\Middleware\\AttemptAuthentication::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\nuwave\\lighthouse\\src\\Support\\Http\\Middleware\\AcceptJson.php",
"line": 27,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Nuwave\\Lighthouse\\Support\\Http\\Middleware\\AcceptJson::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 105,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 683,
"call": "Illuminate\\Pipeline\\Pipeline::then(instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 658,
"call": "Illuminate\\Routing\\Router::runRouteWithinStack(instance of Illuminate\\Routing\\Route, instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 624,
"call": "Illuminate\\Routing\\Router::runRoute(instance of Illuminate\\Http\\Request, instance of Illuminate\\Routing\\Route)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 613,
"call": "Illuminate\\Routing\\Router::dispatchToRoute(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
"line": 170,
"call": "Illuminate\\Routing\\Router::dispatch(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 130,
"call": "Illuminate\\Foundation\\Http\\Kernel::Illuminate\\Foundation\\Http\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\barryvdh\\laravel-debugbar\\src\\Middleware\\InjectDebugbar.php",
"line": 67,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Barryvdh\\Debugbar\\Middleware\\InjectDebugbar::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\app\\Http\\Middleware\\ChangeAppUrlMiddleware.php",
"line": 23,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "App\\Http\\Middleware\\ChangeAppUrlMiddleware::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php",
"line": 21,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php",
"line": 21,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php",
"line": 27,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode.php",
"line": 63,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\fideloper\\proxy\\src\\TrustProxies.php",
"line": 57,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Fideloper\\Proxy\\TrustProxies::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\dingo\\api\\src\\Http\\Middleware\\Request.php",
"line": 111,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 171,
"call": "Dingo\\Api\\Http\\Middleware\\Request::handle(instance of Illuminate\\Http\\Request, instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 105,
"call": "Illuminate\\Pipeline\\Pipeline::Illuminate\\Pipeline\\{closure}(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
"line": 145,
"call": "Illuminate\\Pipeline\\Pipeline::then(instance of Closure)"
},
{
"file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
"line": 110,
"call": "Illuminate\\Foundation\\Http\\Kernel::sendRequestThroughRouter(instance of Illuminate\\Http\\Request)"
},
{
"file": "E:\\wwwroot\\object\\public\\index.php",
"line": 57,
"call": "Illuminate\\Foundation\\Http\\Kernel::handle(instance of Illuminate\\Http\\Request)"
}
]
}
],
"data": {
"onlineStoreThemeAssetCreate": null
}
}
8. Check the SQL statement in the request in Laravel Telescope. as shown in Figure 4
select count(*) as aggregate from `theme_asset` where `theme_id` = 'vogue1'



