Get user roles through Moodle Webservice - api

I’ve been trying to find a way to get a user’s roles back through the Moodle webservice API.
I know there are no endpoints to do this but I cannot retrieve them directly from the database because I do not have access to the client’s database.
Is there another way to do that?

You may code a solution along this lines:
Create a barebones plugin with the usual boilerplate code (version.php and so on), for example a local plugin. You can use this other plugin to generate the boilerplate code: https://moodle.org/plugins/tool_pluginskel
In 'db/services.php' register a new external function and expose it in a new or existing service. Docs here: https://docs.moodle.org/dev/Adding_a_web_service_to_a_plugin and here https://docs.moodle.org/dev/Web_services_API . For example:
$functions = [
'local_myplugin_get_user_roles' => [
'classname' => external::class,
'methodname' => 'get_user_roles',
'description' => 'gets user roles',
'type' => 'read',
],
];
$services = [
'My services' => [
'functions' => [
'local_myplugin_get_user_roles',
],
'enabled' => 1,
'restrictedusers' => 0,
'shortname' => 'local_myplugin',
'downloadfiles' => 0,
'uploadfiles' => 0,
],
];
Write an external class (for example in a external.php file) for your plugin (referenced in the function definition you coded before). In this class write the code for the defined external function (that will fetch the roles for a user given a user id, for example), including the input and output handlers. Example here: https://docs.moodle.org/dev/External_functions_API#externallib.php
Within your external function, to get a list of user roles given a context, userid, etc. you may use the global helper get_user_roles. Do not forget to write in this external function the code needed to validate input parameters and so on.
To properly expose your new service and external function to an external system you need to follow this settings guidelines as a Moodle admin: YOUR_MOODLE_INSTANCE_URL/admin/settings.php?section=webservicesoverview . At the end you will generate a user (web service consumer) and a token, that you can set in your external system to consume the Moodle service.
Happy coding.

Related

Creating auth tokens for a custom model that is not the default User model

How do I create access/api/auth tokens for a different model? From most questions, docs, or tutorials, most are using the default User model.
I read the default doc but it doesn't really say where to substitute the default Model class or how to verify against non-Model classes.
Any suggestions?
To use a different model than User for Laravel Sanctum API authentication.
This is for Laravel 8.
Create new model, php artisan make:model ModelName -m
the flag m is used to instantiate a migration file for this model.
Go to the Model class file and extend it with Illuminate\Foundation\Auth\User, ensure it uses HasApiTokens, and list out your fillable fields for record creation.
...
use Illuminate\Foundation\Auth\User as Authenticatable;
class ModelName extends Authenticatable{
use ..., HasApiTokens;
protected $fillable = [...]
}
Go to config/auth.php and add new provider and new guard.
'guards' => [
...
,
'api' => [
'driver' => 'sanctum',
'provider' => 'model-name',
'hash' => false,
]
],
'providers' => [
...
,
'model-name' => [
'driver' => 'eloquent',
'model' => App\Models\ModelName::class,
]
]
Go to your api routes and wrap your routes as below.
Route::middleware(['auth:sanctum'])->group(function(){
Route::get('/whatever-route-name',function(){
return 'Authenticated';
});
});
Download Postman or your favored API testing tool, send a GET request to [http://localhost:8000/api/whatever-route-name](http://localhost:8000/api/whatever-route-name) , in Headers, ensure Accept has a value of applcation/json, send the request, and it should return an {”message”: “Unauthenticated.”}
Go to your public routes, create a dummy route to create a record for ModelName
After creation ensure that you call $model_name→createToken($model_name→whatever_field)→plaintTextToken; to get the plain text api key.
Go to back to your API test tool, under Authorization, choose Bearer Token and supply the api key returned from above.
The route wrapped in auth:sanctum is now accessible.

Laravel passport ( can`t understand)

I read a lot of articles and watched a lot of videos about Laravel passport but still can not understand some things.
I have an application which works with Laravel 5.5 + vueJs. All requests to the back-end are sent via axios. All my routes are located in api.php
Route::middleware('api')->group(function(){
Route::get('/prepare/', 'CompgenApiController#prepareDefault');
Route::post('/replace/', 'CompgenApiController#replaceImage');
Route::get('/replaceall/', 'CompgenApiController#replaceAllImages');
Route::get('/collage/', 'CompgenApiController#collage'); //#todo переделать на POST
Route::get('/generate/', 'CompgenApiController#generate');
Route::post('/upload/', 'CompgenApiController#userUpload');
Route::post('/reupload/', 'CompgenApiController#moderationReupload');
});
Also I have a VK bot that sends requests to the same routes.
At the moment I have some difficulties. For some routes, I need to check that the user is authorized (but this is an optional condition) and if it is true I need to write user id to the database. For me it was a surprise that
Auth :: check
returned false though I was authorized. After some searches I learned that the session that starts after authorization is not connected with the API and I was recommended to use Passport. I can not understand the following things
Do I need to use a passport if requests are sent from my application from vueJs?
How to register users? Do I have to issue my token for each new user?
How can I verify that the user is authorized?
In some cases I need to check that the user is authorized but if it is not so then do not interfere with the request. How can I do that?
Maybe in my case I do not need a passport at all?
Passport is an oAuth2 server implementation, essentially, it allows you to authenticate users by passing a token with each request. If you do not want to authenticate a user, then you do not need to pass the token and passport doesn't get involved.
In terms of a Laravel app, if you are consuming your API from your own frontend, you probably just want to use the implicit grant. Here's how you set that up:
1) Install passport and add it the PassportServiceProvider to config/app.php
2) php artisan migrate to setup the passport migrations
3) php artisan passport:install - to set up your oAuth server
4) In the User model add the Laravel\Passport\HasApiTokens trait, like so:
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// Other model methods
}
5) Setup the passport routes by adding the following to the boot method of your app\Providers\AuthServiceProviders.php:
\Laravel\Passport\Passport::routes();
6) Change your api driver in config/auth.php to token:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
That sets up passport, now all you need to do to allow your app to consume your api is to add the CreateFreshApiToken Middleware to web in app/Http/Kernel.php, which handles all the token logic:
'web' => [
// ..Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
Now all you need to do to protect a route is to use the auth:api middleware on that route:
Route::middleware('auth:api')->get('/profile','Api\UsersController#edit');
That should all work fine, but you'll also want to register a new user. All you do is add the auth routes as normal to web.php:
Route::post('/login', 'Auth\LoginController#login');
Route::post('/logout', 'Auth\LoginController#logout');
Route::post('/register', 'Auth\RegisterController#register');
You can then simply maks a post request to those routes and Laravel will handle all the token stuff for you.
That handles api routes that require authentication, however, you also mentioned that you want to check if a user is authenticated, but not necessarily lock the route, to do that you can simply use:
Auth::guard('api')->user();
Which will get the authenticated user, so you could do something like:
public function getGreeting(){
$user = Auth::guard('api')->user();
if($user !== null) {
return response()->json(["message" => "Hello {$user->name}"], 200);
}
return response()->json(["message" => "Hello Guest"], 200);
}
That's it. Hopefully, I've covered everything there.

Get user details in Yii framework

I am new to Yii framework and I want to get the user details of current logged in user like userid, username & his avatar and want to add that data in the head tag. I am using basic version on Yii.
How can I get this details?
Yii handles user data in the session using the IdentityInterface.
Let's go step by step.
You can create a class, call it User, which implements IdentityInterface. If connected with the database you can extend it to ActiveRecord, totally up to your architecture.
class User extends ActiveRecord implements IdentityInterface
{
...
}
Add the configuration details into the config file, main.php. I work on advance template, thus its located into fronted/config. Check it for the basic one.
'components' => [
...
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'identityCookie' => ['name' => '_identity-frontend', 'httpOnly' => true],
],
....
];
This tells the app to get the user session details form the common\model\User class. Its in common as I use the same class for backend and the frontend, which is not the case in the basic template.
Make user login into the app
When you get the object of the User class, with valid username and password, use the following code to login the user.
Yii::$app->user->login($user);
To get the value of the user you have following sample
Yii::$app->user->isGuest - This tells you whether the user is logged in or not.
Yii::$app->user->id - Get the id of the user
Yii::$app->user->identity->name - Yii::$app->user->identity will give you access to the entire object of the User class. If you have any other attributes, use the identity and get those. Example, you can have 'avatar', which stores the avatar url, you can get it by Yii::$app->user->identity->avatar.
Finally to logout
Yii::$app->user->logout();
Use the setState method.
In your UserIdentity.php:
public function authenticate()
{
$user=User::model()->find('LOWER(username)=?',array(strtolower($this->username)));
if($user===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if(!$user->validatePassword($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->_id=$user->id;
$this->username=$user->username;
$this->setState("userid",$user->user_id);// set States like this
$this->setState("username",$user->username);
$this->setState("avatar",$user->avatar );
$this->errorCode=self::ERROR_NONE;
}
return $this->errorCode;
}
Now anywhere get these like:
$userid = Yii::app()->user->getState('userid');

Yii2 Restful API - Example to Add a New Action

For buiding restful API using Yii2, does anyone has good example on how to add a new action in a controller? Thanks.
I am not sure if you are asking for extra actions beside CRUD or just for CRUD, so I write in details for both cases.
Firstly, the framework includes \yii\rest\ActiveController that provides typical restful API operation and URL management.
Basically, the controller predefines the CRUD operations as followed:
POST /resource -> actionCreate -> Create the resource
GET /resource/{id} -> actionView -> Read the resource
PUT, PATCH /resource/{id} -> actionUpdate -> Update the resource
DELETE /resource/{id} -> actionDelete -> Delete the resource
GET /resource -> actionIndex -> List all the resources
The URL routing rules and actions definition can be found in \yii\rest\ActiveController, \yii\rest\UrlRule and the respective \yii\rest\*Action.
Secondly, if you want to add extra restful API in the controller, you can simply write your extra actionXxxxx(), and in configuration, add the following url rules under urlManager:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => ['resource'],
'pluralize' => false,
'extraPatterns' => [
'POST {id}/your_preferred_url' => 'xxxxx', // 'xxxxx' refers to 'actionXxxxx'
],
],
],
],
Effectively, this will generate a new routing rule, requesting POST /resource/{id}/your_preferred_url will invoke actionXxxxx of your ResourceController.
Here is a good example using Yii 2 advanced application template
https://github.com/deerawan/yii2-advanced-api
more detail of this project http://budiirawan.com/setup-restful-api-yii2/
also you can use Yii 2 basic application template if you want.
what you have to do is follow this kind of folder structure (v1 for version) (Yii doc -A module may consist of sub-modules.)(GiovanniDerks - backend sub-modules)
-modules
--api
---v1
----controllers
----models

How do I pass in the 'hd' option for OpenID Connect (Oauth2 Login) using the Google Ruby API Client?

The "Using Oauth 2.0 for Login" doc lists the 'hosted domain' parameter as a valid authentication parameter, but using the Google API Client for Ruby linked at the bottom I don't see how to pass it along with my request. Anyone have an example?
OK, wasn't perfect, but I just passed it to the authorization_uri attribute on the authorization object like so
client = Google::APIClient.new
client.authorization.authorization_uri(:hd => 'my_domain')
I still had trouble updating the Addressable::URI object to save the change (kept getting a "comparison of Array with Array failed" error), but this was good enough for me to use.
I couldn't get it to work using the Google::APIClient but managed to get it working using the OAuth2::Client like this
SCOPES = [
'https://www.googleapis.com/auth/userinfo.email'
].join(' ')
client ||= OAuth2::Client.new(G_API_CLIENT, G_API_SECRET, {
:site => 'https://accounts.google.com',
:authorize_url => "/o/oauth2/auth",
:token_url => "/o/oauth2/token"
})
...
redirect client.auth_code.authorize_url(:redirect_uri => redirect_uri,:scope => SCOPES,:hd => 'yourdomain.com')