接入集团auth流程
前言
一直对集团的auth系统很感兴趣,所以这次记录下接入集团auth的流程。如果后期有时间,会补充具体的auth实现细节。
正文
一、实现思想
1. 实现思想
明确几个名词:接入方,管理方。接入方指的是:要接入auth系统的这些应用;管理方指的是:管理应用程序的地方,也就是我们的auth系统。
auth的大致的实现逻辑就是:需要进行权限验证的接入方的请求url在进行权限验证的时候把所有的验证、管理、授权操作都通过发送请求的方式来让管理方来处理。那么就可以理解为:用户有没有登录的权限,有没有某个请求的权限都是通过管理方来判断的。
具体流程图如下所示:
二、实现代码
1. url请求需要经过中间件
2. 请求中间件代码
class Authenticate { public function handle(Request $request, Closure $next) { if (!Aus::checkLogin()) { return Aus::goLogin($request->url()); } $uri = "/".trim($request->route()->uri, "/"); if (!Aus::authorize($uri)) { $msg = '对不起,你没有对应的权限,请联系管理员!'; if ($request->ajax()) { $ajaxResp = json_encode(['code' => 401, 'message' => $msg], JSON_UNESCAPED_UNICODE); return response($ajaxResp, 200); } return response("<h2>$msg</h2>", 401); } return $next($request); } }
class AuthenticateService { private static $notAuthList = ["/"]; /** * 验证登陆 * * @return bool */ public static function checkLogin() { if (Config::get('auto_auth.ignore_auth', false)) { return true; } return Session::has('user') ? true : false; } /** * 鉴权 * @param $uri * @return bool */ public static function authorize($uri) { if (Config::get('auto_auth.ignore_auth', false)) { return true; } // 不用校验的URI if (in_array($uri, self::$notAuthList)) { return true; } if (!Session::has('user.permissions')) { return false; } if (!Session::has('user.token')) { return false; } $user = Session::get('user'); foreach ($user['permissions'] as $permission) { $permission = rtrim($permission, '/'); if ($permission) { $permission = '#'.$permission.'#'; if (@preg_match($permission, $uri)) { return true; } } } return false; } /** * 通过Auth系统登陆 * * @param string $token * * @return array|bool */ public static function getUserByToken($token) { $ssoCheckUrl = Config::get('auto_auth.url') . '/sso/checktoken?token=' . $token; $httpResponse = file_get_contents($ssoCheckUrl); $content = []; if ($httpResponse) { $content = json_decode($httpResponse, true); } if (isset($content['code']) && 0 == $content['code']) { $allPermissions = array_get($content, 'data.permissions', []); $permissions = []; $baseRole = null; foreach ($allPermissions as $permission) { if ($permission['app_key'] == Config::get('auto_auth.app_key')) { $permissions[] = $permission['regex']; } } $userInfo = [ 'user_id' => $content['data']['account'], 'username' => $content['data']['name'], 'email' => $content['data']['email'], 'mobile' => $content['data']['mobile'], 'ttl' => $content['data']['ttl'], 'token' => $token, 'permissions' => $permissions, 'baseRule' => !is_null($baseRole) ?? 0, ]; session(['user' => $userInfo]); return $userInfo; } return false; } /** * 跳转登陆页面 * @param $targetUrl * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public static function goLogin($targetUrl) { $params = [ 'tarurl' => $targetUrl, 'app_key' => Config::get('auto_auth.app_key'), ]; $params_str = http_build_query($params); $login_url = Config::get('auto_auth.url') . Config::get('auto_auth.api_list.login') . '?' . $params_str; return redirect($login_url); } /** * 登出 * @param $targetUrl * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public static function goLogout($targetUrl) { $params = [ 'tarurl' => $targetUrl, 'app_key' => Config::get('auto_auth.app_key'), 'token' => Session::get('user.token'), ]; $params_str = http_build_query($params); $logout_url = Config::get('auto_auth.url') . Config::get('auto_auth.api_list.login') . '?' . $params_str; Session::forget('user'); return redirect($logout_url); } // 获取当前登录用户信息 public static function getAuthUser() { if (!self::checkLogin()) { return []; } return Session::get('user'); } /** * 获取当前登录用户的ID */ public static function getLoginUserId() { return array_get(Session::get('user'), 'user_id', 0); } /** * 获取当前登录用户的ID */ public static function getLoginMobile() { return array_get(Session::get('user'), 'mobile', 0); } /** * 获取登陆用户的邮箱 */ public static function getLoginEmail() { return array_get(Session::get('user'), 'email', ''); } /** * 获取当前登录用户的名字 */ public static function getLoginUserName() { return array_get(Session::get('user'), 'username', 'admin'); } /** * 获取当前登录用户权限列表(正则表达式) * @return array */ public static function getUserPermissions() { $user = self::getAuthUser(); return array_get($user, 'permissions', []); } /** * 获取授权菜单 * @param $list * @return mixed */ public static function getAuthMenu($list) { if (Config::get('auto_auth.ignore_auth', false)) { return $list; } $result = []; $parentCount = []; foreach ($list as $item) { //父级菜单直接通过 if ($item['pid'] == 0) { $result[] = $item; } else { //有权限的子菜单 if (self::authorize($item['auth_url'])) { $result[] = $item; //标记被使用到的父级菜单 $parentCount[$item['pid']] = 1; } } } //去掉没有用过的父级菜单 foreach ($result as $k => $item) { if ($item['pid'] == 0 && empty($parentCount[$item['id']])) { unset($result[$k]); } } return $result; } }
Route::group(['prefix' => '/sso', 'namespace' => 'Auth'], function () { Route::get('/login', 'SsoController@login'); Route::get('/jump', 'SsoController@jump'); Route::get('/logout', 'SsoController@logout'); if(env('APP_ENV', 'local') == 'local') { Route::get('/mockLogin', 'SsoController@mockLogin'); } });
class SsoController extends Controller { /** * 登陆 */ public function login(Request $request) { $validator = Validator::make( $request->all(), [ 'action' => 'required|in:login,logout', 'token' => 'required', ] ); if ($validator->fails()) { return -1; } if ('login' != $request->get('action')) { return -2; } $token = $request->get('token'); $user = Aus::getUserByToken($token); if (empty($user)) { return -2; } return response($request->callback . "('" . Config::get('auto_auth.app_key') . "')") ->withCookie('token', $request->token, 10000000) ->header('p3p', 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'); } public function logout(Request $request) { $url = $request->root(); return Aus::goLogout($url); } public function jump() { return Aus::goLogin("http://".$_SERVER['HTTP_HOST']."/index/home"); } public function mockLogin(Request $request) { $userInfo = [ 'user_id' => array_get($request, 'user_id'), 'username' => array_get($request, 'username', ''), 'email' => array_get($request, 'email', ''), 'mobile' => array_get($request, 'mobile', ''), 'ttl' => 3600*100, ]; session(['user' => $userInfo]); } }
AUTO_AUTH_IGNORE_AUTH=false #AUTO_AUTH_URL= AUTO_AUTH_URL= AUTO_AUTH_APP_URL= AUTO_AUTH_APP_KEY= AUTO_AUTH_API_LIST_LOGIN=
3. 后台配置项目相关内容
三、总结
总的流程是:
添加中间件代码 => 修改中间件涉及的代码 => 修改env配置 => 后端配置
注意:测试环境可用dev4
后序
不积跬步无以至千里,不积小流无以成江海