Manuel:CORS/fr
Cette page détaille l'utilisation des requêtes CORS dans le code JavaScript pour communiquer entre les wikis de différents domaines.
L'API MediaWiki supporte les requêtes CORS (cross-origin resource sharing) (en) si $CrossSiteAJAXdomains est activé.
- authenticated requests using cookies, if
$wgCrossSiteAJAXdomains
is enabled on the remote wiki.
C'est utile sur les sites Wikimedia, par exemple, pour permettre le téléversement d'images directement sur Commons depuis Wikipédia avec l'interface mobile.
- includes but is not limited to authenticated requests in which a logged in user at the remote wiki performs an action on behalf of the local wiki
- authenticated requests using OAuth.
- anonymous, non-authenticated requests, used mainly for more limited actions such as fetching publicly available data.
Configuration
The Action API and REST API come with different requirements for handling CORS requests.
Action API
For requests to the Action API, CORS is enabled by default, but the request URL must include in its query string either the origin
parameter, with an appropriate value, or the crossorigin
parameter.
Notez que origin
est une partie de l'URL parce que les requêtes POST de CORS sont préarrangées et que le paramètres de l'origine doit être inclus dans la requête de préarrangement.
- Cela doit correspondre à l'une des valeurs de
$wgCrossSiteAJAXdomains
sur le wiki distant. Note that the value of the origin parameter must begin with the HTTPS protocol (e.g.https://mediawiki.org
), even if$wgCrossSiteAJAXdomains
accepts values without it. - To allow authenticated requests using OAuth, use
crossorigin
(with any value) along with an appropriateAuthorization
request header. You will probably want to use OAuth 2 rather than OAuth 1.0a; see OAuth/Pour les développeurs for details. Depuis MediaWiki 1.44 • change 1118583
Pour les requêtes anonymes, le paramètre origin
de la chaîne de requête peut être initialisé à *
ce qui permettra les requêtes de n'importe où.
REST API
To allow authenticated requests, you can do either of two things:
- use the OAuth extension (recommended approach).
The REST API was designed to be used with the OAuth extension for user authentication and authorization.
- set $wgRestAllowCrossOriginCookieAuth to true so that any origin specified in $wgCrossSiteAJAXdomains may send session cookies for authorization in the REST API.
To allow anonymous requests to the REST API, $wgAllowCrossOrigin must be set to true
on the remote wiki.
This will set Access-Control-Allow-Origin
in the header to *
.
Unlike the Action API, the REST API does not come with an origin parameter in the request URL.
JavaScript methods
Using mediawiki.ForeignApi
MediaWiki's ResourceLoader offers the mediawiki.ForeignApi
module, which is an extension of mediawiki.api
and automatically handles the details for you. It offers two constructors for enabling CORS:
- For requests to the Action API, use
mw.ForeignApi
. (introduit dans 1.26)
- For requests to the REST API, use
mw.ForeignRest
. (introduit dans 1.36)
Examples are given below. To use mw.ForeignApi
or mw.ForeignRest
, extensions should set mediawiki.ForeignApi
as a ResourceLoader module dependency in extension.json.
If you use mw.ForeignApi()
with a POST request (.post()
), then origin=*
will be included automatically. If you need to use mw.ForeignApi() with a GET request (.get()
), make sure that origin=*
, if required, is appended directly to the URL (not to the query string).
If it is necessary for the requested action that the user at the foreign wiki is logged in, pass the assert: 'user'
parameter to get()
/post()
. To assert that the user at the foreign wiki has a specific username, pass the assertuser
parameter with the desired username.
Using Fetch
If the GET request can be made anonymously, you can also use Fetch (the modern, Promise-based replacement for XMLHttpRequest).
Using jQuery.ajax
Si vous ne voulez pas utiliser mediawiki.api pour une raison quelconque, ou si vous êtes intéressé de connaitre son fonctionnement à un niveau plus bas, voici comment implémenter la même fonctionalité en utilisant directement les fonctions AJAX jQuery. Vous pourriez même utiliser directement XMLHttpRequest
.
Examples are given below.
Si vous voulez que le navigateur utilise les cookies qu'il pourrait avoir concernant le domaine, afin de garder l'utilisateur actuel connecté, vous devez aussi initialiser le champ withCredentials
de XMLHttpRequest
à true
.
Examples
Dans les exemples ci-dessous, nous supposons que le wiki local à partir duquel la requête a été émise est www.mediawiki.org
, et que le wiki distant - celui vers lequel la requête est dirigée - est en.wikipedia.org
.
<span id="Using_mw.ForeignApi
">
Utiliser mw.ForeignApi
Authenticated requests
Un exemple qui vérifie si l'utilisateur est connecté sur le wiki distant :
await mw.loader.using( 'mediawiki.ForeignApi' )
const api = new mw.ForeignApi( 'https://en.wikipedia.org/w/api.php' );
const data = await api.get( { action: 'query', meta: 'userinfo' } );
alert( `Foreign user ${data.query.userinfo.name} (ID ${data.query.userinfo.id})` );
Un exemple de base d'API d'écriture. Nous demandons un jeton csrf
et l'utilisons pour initialiser une préférence utilisateur persistante qu'un gadget pourra utiliser après cela :
await mw.loader.using( 'mediawiki.ForeignApi' );
const api = new mw.ForeignApi( 'https://en.wikipedia.org/w/api.php' );
const data = await api.get( { action: 'query', meta: 'tokens' } );
await api.post( {
action: 'options',
token: data.query.tokens.csrftoken,
optionname: 'userjs-test',
optionvalue: 'Hello world!'
} );
Le même exemple peut être réécrit plus succintement en utilisant quelques méthodes de mediawiki.api helper, qui sont disponibles également pour ForeignApi :
await mw.loader.using( 'mediawiki.ForeignApi' );
const api = new mw.ForeignApi( 'https://en.wikipedia.org/w/api.php' );
await api.postWithToken( 'options', {
action: 'options',
optionname: 'userjs-test',
optionvalue: 'Hello world!'
} );
Requêtes anonymes
Si le wiki cible n'accepte pas les requêtes inter-origines, ou si vous n'avez pas besoin de réaliser des actions d'écriture ou de lire des informations restreintes et que vous voulez éviter la surcharge, vous pouvez alors initialiser l'option anonymous
dans le constructeur mediawiki.ForeignApi
:
await mw.loader.using( 'mediawiki.ForeignApi' )
const api = new mw.ForeignApi( 'https://en.wikipedia.org/w/api.php', { anonymous: true } );
...
Using mw.ForeignRest
Exemple utilisant l'API REST :
var api = new mw.ForeignRest( 'https://commons.wikimedia.org/w/rest.php/v1' );
await api.get( '/page/Main_Page/html' );
An example that queries pages whose page names start with "Test" from Wikimedia Commons (and then logs the results in the browser):
var value = "Test";
var actionApi = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' );
const api = new mw.ForeignRest(
'https://commons.wikimedia.org/w/rest.php/v1',
actionApi,
{ anonymous: true }
);
api.get( '/search/title', {
limit: '10',
q: `${ encodeURIComponent( value ) }`,
origin: '*'
} )
.done( function ( data ) {
console.log( data );
} );
Using Fetch
Get
var apiEndpoint = "https://commons.wikimedia.org/w/api.php";
var params = "action=query&list=allimages&ailimit=3&format=json";
/**
* Send the request to get the images
*/
fetch( apiEndpoint + "?" + params + "&origin=*" )
.then(function(response){
return response.json();
})
.then(function(response) {
var allimages = response.query.allimages; // Process the output to get the image names
Object.keys(allimages).forEach(function(key) {
console.log(allimages[key].name);
});
});
Post
var apiEndpoint = 'https://test.wikipedia.org/w/api.php';
var params = {
action: 'edit',
title: 'Wikipedia:Sandbox',
text: 'Hello World',
summary: 'Hello World',
format: 'json',
formatversion: '2',
crossorigin: ''
}
// Replace with actual OAuth 2 token
var oauthToken = "OAuthAccessToken";
/**
* Get CSRF token
*/
var tokenQuery = {
action: 'query',
meta: 'tokens',
format: 'json',
formatversion: '2',
crossorigin: ''
};
var queryURL = new URL(apiEndpoint);
queryURL.search = new URLSearchParams(tokenQuery);
fetch(queryURL, {method: 'GET', headers: {'Authorization': 'Bearer ' + oauthToken}})
.then(function(response){return response.text()})
.then(function(data){
try {data=JSON.parse(data);} catch (e) {console.error(e);}
params.token = data?.query?.tokens?.csrftoken;
if (params.token) {
/**
* Post edit.
* Action API requires data be posted as application/x-www-form-urlencoded (URLSearchParams) or multipart/form-data, rather than application/json (T212988)
*/
var postBody = new URLSearchParams();
queryURL = new URL(apiEndpoint);
Object.keys(params).forEach( key => {
if ( key == 'action' || key == 'origin' || key == 'crossorigin' ) {
queryURL.searchParams.append(key, params[key]);
} else {
postBody.append(key, params[key]);
}
});
fetch(queryURL, {method: 'POST', headers: {'Authorization': 'Bearer ' + oauthToken}, body: postBody})
.then(function(response){return response.text()})
.then(function(data){
try {data=JSON.parse(data);} catch (e) {console.error(e);}
var result = data?.edit?.result;
if (result) {
console.log(result);
} else {
console.error("Error posting edit!");
}
});
} else {
console.error("Error retrieving CSRF token!");
}
});
Utiliser les méthodes jQuery
Un exemple qui vérifie si l'utilisateur est connecté sur le wiki distant :
const { query } = await $.ajax( {
url: 'https://en.wikipedia.org/w/api.php',
data: {
action: 'query',
meta: 'userinfo',
format: 'json',
origin: 'https://www.mediawiki.org'
},
xhrFields: {
withCredentials: true
},
dataType: 'json'
} );
alert( `Foreign user ${query.userinfo.name} (ID ${query.userinfo.id})` );
Un exemple de base d'API d'écriture :
const { query } = await $.ajax( {
url: 'https://en.wikipedia.org/w/api.php',
data: {
action: 'query',
meta: 'tokens',
format: 'json',
origin: 'https://www.mediawiki.org'
},
xhrFields: {
withCredentials: true
},
dataType: 'json'
} );
await $.ajax( {
url: 'https://en.wikipedia.org/w/api.php?origin=https://www.mediawiki.org',
method: 'POST',
data: {
action: 'options',
format: 'json',
token: query.tokens.csrftoken,
optionname: 'userjs-test',
optionvalue: 'Hello world!'
},
xhrFields: {
withCredentials: true
},
dataType: 'json'
} );
OAuth authentication examples
Version de MediaWiki : | 1.44 Gerrit change 1118583 |
The following two external examples show how to use OAuth 2 to make authenticated CORS requests:
- Vuetify app with Wikimedia OAuth login, focusing on the details of the authorization flow, with links to runnable code
- webapp-clientside-vite-guestbook m3api example, a runnable example app for a set of JavaScript libraries you can use
Extensions au mécanisme
CentralAuth
Version de MediaWiki : | ≥ 1.26 |
CentralAuth permet à votre code d'authentifier sur le wiki distant l'utilisateur actuellement connecté sur le wiki local en utilisant un centralauthtoken. Ceci garanti que le même compte associé sera utilisé pour les actions sur les deux wikis, au contraire d'un CORS régulier (qui nécessite que l'utilisateur se soit auparavent connecté au wiki distant).
Si à la fois le wiki local et le wiki distant ont installé CentralAuth, le mécanisme mediawiki.ForeignApi est étendu de la mème manière pour gérer cela à votre place. Pour l'implémenter vous-même, voir centralauthtoken pour les instructions sur la manière d'acquérir un jeton (du wiki local) et le passer à une requête (au wiki distant).
Autres solutions
Pour les requêtes anonymes vous pouvez utiliser le format JSONP à la place. Ceci est plus simple mais un peu moins sécurisé (il accède et exécute du code JavaScript arbitraire sur le wiki si bien qu'un assaillant qui prendrait la main sur le site MediaWiki aurait un vecteur XSS sur le site distant).