增加获取头像的API

master
落雨楓 2 years ago
parent cb158d7398
commit 9a10a6b5e7

@ -29,7 +29,8 @@
"UserLogoutComplete": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onLogout", "UserLogoutComplete": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onLogout",
"GetPreferences": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onGetPreferences", "GetPreferences": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onGetPreferences",
"SkinTemplateNavigation::Universal": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onSkinTemplateUniversalNavigation", "SkinTemplateNavigation::Universal": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onSkinTemplateUniversalNavigation",
"ResourceLoaderGetConfigVars": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onResourceLoaderGetConfigVars" "ResourceLoaderGetConfigVars": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onResourceLoaderGetConfigVars",
"Isekai::GetUserAvatar": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onGetUserAvatar"
}, },
"ExtensionMessagesFiles": { "ExtensionMessagesFiles": {
"IsekaiOIDCAlias": "IsekaiOIDC.alias.php" "IsekaiOIDCAlias": "IsekaiOIDC.alias.php"
@ -50,7 +51,10 @@
} }
}, },
"APIModules": { "APIModules": {
"oidcwebhook": "Isekai\\OIDC\\ApiOidcWebhook" "oidcwebhook": "Isekai\\OIDC\\ApiOIDCWebhook"
},
"APIPropModules": {
"oidcavatar": "Isekai\\OIDC\\ApiOIDCAvatar"
}, },
"config": { "config": {
"IsekaiOIDC": { "IsekaiOIDC": {

@ -10,6 +10,13 @@
"apihelp-oidcwebhook-param-provider": "Provider", "apihelp-oidcwebhook-param-provider": "Provider",
"apihelp-oidcwebhook-param-key": "Secret Key", "apihelp-oidcwebhook-param-key": "Secret Key",
"apihelp-query+oidcavatar-summary": "Get user avatar from OpenID Connection Provider",
"apihelp-query+oidcavatar-param-username": "Username in local Wiki",
"apihelp-query+oidcavatar-param-userid": "User ID in local Wiki",
"apihelp-query+oidcavatar-param-size": "Avatar size",
"apihelp-query+oidcavatar-param-redirect": "Redirect to avatar URL",
"isekaioidc-api-example-isekaioidcavatar": "Get avatar of user 'Example' in size 128px",
"isekaioidc-api-provider-not-supported": "Provider Unsupported", "isekaioidc-api-provider-not-supported": "Provider Unsupported",
"isekaioidc-api-key-invalid": "API Key invalid", "isekaioidc-api-key-invalid": "API Key invalid",
"isekaioidc-api-post-body-invalid": "POST Body format invalid", "isekaioidc-api-post-body-invalid": "POST Body format invalid",

@ -10,6 +10,13 @@
"apihelp-oidcwebhook-param-provider": "Provider", "apihelp-oidcwebhook-param-provider": "Provider",
"apihelp-oidcwebhook-param-key": "Secret Key", "apihelp-oidcwebhook-param-key": "Secret Key",
"apihelp-query+oidcavatar-summary": "从 OpenID Connection 用户中心获取用户头像",
"apihelp-query+oidcavatar-param-username": "本地Wiki用户名",
"apihelp-query+oidcavatar-param-userid": "本地Wiki用户ID",
"apihelp-query+oidcavatar-param-size": "头像大小",
"apihelp-query+oidcavatar-param-redirect": "重定向到头像URL",
"isekaioidc-api-example-isekaioidcavatar": "获取用户名为“Example”的用户的128px头像",
"isekaioidc-api-provider-not-supported": "不支持的Provider", "isekaioidc-api-provider-not-supported": "不支持的Provider",
"isekaioidc-api-key-invalid": "API Key错误", "isekaioidc-api-key-invalid": "API Key错误",
"isekaioidc-api-post-body-invalid": "POST Body格式错误", "isekaioidc-api-post-body-invalid": "POST Body格式错误",

@ -0,0 +1,97 @@
<?php
namespace Isekai\OIDC;
use ApiBase;
use ApiQueryBase;
use Exception;
use Exif;
use MediaWiki\MediaWikiServices;
use Wikimedia\ParamValidator\ParamValidator;
use User;
class ApiOIDCAvatar extends ApiQueryBase {
public function __construct( $main, $method ) {
parent::__construct( $main, $method );
}
public function execute() {
$services = MediaWikiServices::getInstance();
$config = $services->getMainConfig();
$wgIsekaiOIDC = $config->get('IsekaiOIDC');
//$this->requireOnlyOneParameter('username', 'userid');
$userid = $this->getParameter('userid');
$username = $this->getParameter('username');
$userFactory = $services->getUserFactory();
if ($userid) {
$user = $userFactory->newFromId($userid);
} else {
$user = $userFactory->newFromName($username);
}
if (!$user) {
$this->dieWithError('isekaioidc-api-user-not-found', 'isekaioidc-api-user-not-found');
}
$size = $this->getParameter('size');
$avatarUrl = '';
$hookContainer = $services->getHookContainer();
$hookContainer->run('Isekai::GetUserAvatar', [&$avatarUrl, $size, $user]);
if (empty($avatarUrl)) {
if (isset($wgIsekaiOIDC['defaultAvatarUrl'])) {
$avatarUrl = $wgIsekaiOIDC['defaultAvatarUrl'];
} else {
$this->dieWithError('isekaioidc-api-user-avatar-not-found', 'isekaioidc-api-user-avatar-not-found', [
'userid' => $userid,
'username' => $username,
]);
}
}
if ($this->getParameter('redirect')) {
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $avatarUrl);
header('Cache-Control: public, max-age=86400');
exit();
} else {
$this->getResult()->addValue('query', 'oidcavatar', $avatarUrl);
}
}
public function getAllowedParams() {
return [
'username' => [
ParamValidator::PARAM_DEFAULT => null,
ParamValidator::PARAM_TYPE => 'string',
],
'userid' => [
ParamValidator::PARAM_DEFAULT => null,
ParamValidator::PARAM_TYPE => 'integer',
],
'size' => [
ParamValidator::PARAM_DEFAULT => 128,
ParamValidator::PARAM_TYPE => 'integer',
],
'redirect' => [
ParamValidator::PARAM_DEFAULT => false,
ParamValidator::PARAM_TYPE => 'boolean',
]
];
}
public function getExamplesMessages() {
return [
'action=query&prop=oidcavatar&username=Example&size=128' => 'isekaioidc-api-example-isekaioidcavatar',
];
}
public function getCacheMode($params) {
return 'public';
}
}

@ -6,13 +6,16 @@ use ApiBase;
use MediaWiki\MediaWikiServices; use MediaWiki\MediaWikiServices;
use Wikimedia\ParamValidator\ParamValidator; use Wikimedia\ParamValidator\ParamValidator;
class ApiOidcWebhook extends ApiBase { class ApiOIDCWebhook extends ApiBase {
public function __construct( $main, $method ) { public function __construct( $main, $method ) {
parent::__construct( $main->getMain(), $method ); parent::__construct( $main->getMain(), $method );
} }
public function execute() { public function execute() {
global $wgIsekaiOIDC; $services = MediaWikiServices::getInstance();
$config = $services->getMainConfig();
$wgIsekaiOIDC = $config->get('IsekaiOIDC');
$queryValues = $this->getRequest()->getQueryValues(); $queryValues = $this->getRequest()->getQueryValues();
$provider = ''; $provider = '';
if (isset($queryValues['provider'])) { if (isset($queryValues['provider'])) {
@ -36,6 +39,10 @@ class ApiOidcWebhook extends ApiBase {
} }
private function keycloakCallback() { private function keycloakCallback() {
$services = MediaWikiServices::getInstance();
$config = $services->getMainConfig();
$wgIsekaiOIDC = $config->get('IsekaiOIDC');
if (!$this->getRequest()->wasPosted()) { if (!$this->getRequest()->wasPosted()) {
$this->addError('isekaioidc-api-post-body-invalid'); $this->addError('isekaioidc-api-post-body-invalid');
return; return;
@ -47,7 +54,6 @@ class ApiOidcWebhook extends ApiBase {
$this->addError('isekaioidc-api-post-body-invalid'); $this->addError('isekaioidc-api-post-body-invalid');
return; return;
} }
global $wgIsekaiOIDC;
$realm = $wgIsekaiOIDC['realm']; $realm = $wgIsekaiOIDC['realm'];
$apiMode = $wgIsekaiOIDC['apiMode'] ?? 'oauth'; $apiMode = $wgIsekaiOIDC['apiMode'] ?? 'oauth';
@ -76,7 +82,7 @@ class ApiOidcWebhook extends ApiBase {
'phone' => $userInfo->phone_number, 'phone' => $userInfo->phone_number,
]; ];
$user = MediaWikiServices::getInstance()->getUserFactory()->newFromId($userId); $user = $services->getUserFactory()->newFromId($userId);
IsekaiOIDCAuth::updateUserInfo($user, $newProfile); IsekaiOIDCAuth::updateUserInfo($user, $newProfile);
} }
$this->getResult()->addValue(null, 'webhook', 1); $this->getResult()->addValue(null, 'webhook', 1);

@ -69,10 +69,13 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider {
* @inheritDoc * @inheritDoc
*/ */
public function continuePrimaryAuthentication( array $reqs ) { public function continuePrimaryAuthentication( array $reqs ) {
global $wgIsekaiOIDC; $services = MediaWikiServices::getInstance();
$config = $wgIsekaiOIDC; $config = $services->getMainConfig()->get('IsekaiOIDC');
$oidc = self::getOpenIDConnectClient(); $oidc = self::getOpenIDConnectClient();
$requestCtx = RequestContext::getMain();
if ($oidc->authenticate()) { if ($oidc->authenticate()) {
$accessToken = $oidc->getAccessToken(); $accessToken = $oidc->getAccessToken();
$refreshToken = $oidc->getRefreshToken(); $refreshToken = $oidc->getRefreshToken();
@ -88,7 +91,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider {
} }
$authManager = MediaWikiServices::getInstance()->getAuthManager(); $authManager = MediaWikiServices::getInstance()->getAuthManager();
$request = RequestContext::getMain()->getRequest(); $request = $requestCtx->getRequest();
$session = $request->getSession(); $session = $request->getSession();
$session->clear('AuthManager::AutoCreateBlacklist'); // 防止缓存检测 $session->clear('AuthManager::AutoCreateBlacklist'); // 防止缓存检测
@ -228,14 +231,15 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider {
} }
public static function getOpenIDConnectClient() { public static function getOpenIDConnectClient() {
global $wgIsekaiOIDC; $services = MediaWikiServices::getInstance();
if (!is_array($wgIsekaiOIDC)) { $config = $services->getMainConfig()->get('IsekaiOIDC');
if (!is_array($config)) {
wfDebugLog( self::LOG_TAG, 'wgIsekaiOIDC not set' . wfDebugLog( self::LOG_TAG, 'wgIsekaiOIDC not set' .
PHP_EOL ); PHP_EOL );
throw new Exception('wgIsekaiOIDC not set'); throw new Exception('wgIsekaiOIDC not set');
} }
$config = $wgIsekaiOIDC;
if (!isset($config['endpoint']) || !isset($config['clientID']) || !isset($config['clientSecret'])) { if (!isset($config['endpoint']) || !isset($config['clientID']) || !isset($config['clientSecret'])) {
wfDebugLog( self::LOG_TAG, 'wgIsekaiOIDC not valid' . wfDebugLog( self::LOG_TAG, 'wgIsekaiOIDC not valid' .
PHP_EOL ); PHP_EOL );
@ -251,7 +255,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider {
$oidc->setRedirectURL( $redirectURL ); $oidc->setRedirectURL( $redirectURL );
wfDebugLog( self::LOG_TAG, 'Redirect URL: ' . $redirectURL ); wfDebugLog( self::LOG_TAG, 'Redirect URL: ' . $redirectURL );
if ( isset( $_REQUEST['forcelogin'] ) ) { if ( isset( $_REQUEST['force'] ) || isset( $_REQUEST['forcelogin'] ) ) {
$oidc->addAuthParam( [ 'prompt' => 'login' ] ); $oidc->addAuthParam( [ 'prompt' => 'login' ] );
} }
if ( isset( $config['authparam'] ) && if ( isset( $config['authparam'] ) &&

@ -44,7 +44,8 @@ class IsekaiOIDCAuthHooks {
* @param OutputPage $out * @param OutputPage $out
*/ */
public static function onBeforePageDisplay($out) { public static function onBeforePageDisplay($out) {
global $wgIsekaiOIDC; $services = MediaWikiServices::getInstance();
$wgIsekaiOIDC = $services->getMainConfig()->get('IsekaiOIDC');
if (isset($wgIsekaiOIDC['syncLogout']) && $wgIsekaiOIDC['syncLogout']) { if (isset($wgIsekaiOIDC['syncLogout']) && $wgIsekaiOIDC['syncLogout']) {
$title = $out->getTitle(); $title = $out->getTitle();
@ -97,7 +98,9 @@ class IsekaiOIDCAuthHooks {
} }
public static function onGetPreferences(\User $user, &$preferences) { public static function onGetPreferences(\User $user, &$preferences) {
global $wgIsekaiOIDC; $services = MediaWikiServices::getInstance();
$wgIsekaiOIDC = $services->getMainConfig()->get('IsekaiOIDC');
$profileUrl = $wgIsekaiOIDC['endpoint'] . 'account/'; $profileUrl = $wgIsekaiOIDC['endpoint'] . 'account/';
$referrer = $wgIsekaiOIDC['clientID']; $referrer = $wgIsekaiOIDC['clientID'];
$referrerUri = Title::newFromText('Special:Preferences')->getCanonicalURL(); $referrerUri = Title::newFromText('Special:Preferences')->getCanonicalURL();
@ -159,10 +162,45 @@ class IsekaiOIDCAuthHooks {
* @return bool * @return bool
*/ */
public static function onResourceLoaderGetConfigVars(&$vars, $skin, $config) { public static function onResourceLoaderGetConfigVars(&$vars, $skin, $config) {
global $wgIsekaiOIDC; $services = MediaWikiServices::getInstance();
$wgIsekaiOIDC = $services->getMainConfig()->get('IsekaiOIDC');
if (isset($wgIsekaiOIDC['avatarUrl'])) { if (isset($wgIsekaiOIDC['avatarUrl'])) {
$vars['wgAvatarTemplate'] = $wgIsekaiOIDC['avatarUrl']; $vars['wgAvatarTemplate'] = $wgIsekaiOIDC['avatarUrl'];
} }
return true; return true;
} }
public static function onGetUserAvatar(&$avatarUrl, $size, $user) {
$services = MediaWikiServices::getInstance();
$config = $services->getMainConfig();
$wgIsekaiOIDC = $config->get('IsekaiOIDC');
if (isset($wgIsekaiOIDC['avatarUrl'])) {
list($subject, $accessToken, $refreshToken) = IsekaiOIDCAuth::findOidcDataByUserId($user->getId());
$avatarFinded = false;
if ($subject) {
$avatarUrl = str_replace(['{openid}', '{username}'], [urlencode($subject), urlencode($user->getName())], $wgIsekaiOIDC['avatarUrl']);
$avatarFinded = true;
} else {
if (isset($wgIsekaiOIDC['defaultAvatarUrl'])) {
$avatarUrl = $wgIsekaiOIDC['defaultAvatarUrl'];
$avatarFinded = true;
}
}
if ($avatarFinded) {
if ($size <= 64) {
$avatarUrl = "$avatarUrl?size=md";
} else if ($size <= 128) {
$avatarUrl = "$avatarUrl?size=lg";
} else if ($size <= 256) {
$avatarUrl = "$avatarUrl?size=xl";
} else {
$avatarUrl = "$avatarUrl?size=xxl";
}
}
}
return true;
}
} }

Loading…
Cancel
Save