PsyUserSso.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Encore\Admin\Facades\Admin;
  5. use Illuminate\Log\Logger;
  6. use Illuminate\Support\Facades\DB;
  7. use Illuminate\Support\Facades\Log;
  8. use Illuminate\Support\Facades\Redis;
  9. use Illuminate\Support\Facades\Validator;
  10. use Monolog\Handler\RotatingFileHandler;
  11. //站点用户验证
  12. class PsyUserSso
  13. {
  14. const USER_DATA_URL = "/api.php";
  15. private $url = "/admin/ssoIndex";
  16. /**
  17. * Handle an incoming request.
  18. *
  19. * @param \Illuminate\Http\Request $request
  20. * @param \Closure $next
  21. * @return mixed
  22. */
  23. public function handle($request, Closure $next)
  24. {
  25. if (Admin::guard()->check()){
  26. return $next($request);
  27. }
  28. $sign = $request->get("sign");
  29. $signData = $request->only(array("task","appid","open_id","version","go_url"));
  30. $config = config("console.remote_sso");
  31. if ($config["appid"] != $signData["appid"]){
  32. throw new \Exception("appid非法参数:{$signData["appid"]}");
  33. }
  34. $paramsData = $request->except(array("appid","op", "task","version","sign","go_url"));
  35. $userModelClass = config('admin.database.users_model');
  36. $userModel = new $userModelClass();
  37. if (Admin::guard()->check() && Admin::user()->third_openid == $signData["open_id"]){
  38. //更新用户信息
  39. $res = DB::table($userModel::query()->getModel()->getTable())->where(
  40. array("id"=>Admin::user()->id)
  41. )->update(array(
  42. "third_openid"=>$signData["open_id"],
  43. "workstation_id"=>$paramsData['outside_c_id'],
  44. "workstation_name"=>$paramsData['visit_title']
  45. ));
  46. return $next($request);
  47. }
  48. $userData = $this->getUserData($signData["open_id"]);//下面需要获取用户账号、昵称、头像
  49. // $nowSign=$this->getSign(
  50. // $paramsData,
  51. // "core",
  52. // $signData["task"],
  53. // $signData["version"]
  54. // );
  55. // if ($nowSign != $sign){
  56. // throw new \Exception("签名验证不能通过:sign:{$sign}、nowSign:{$nowSign}");
  57. // }
  58. $checkUserData = $userModel::query()
  59. ->where(
  60. array(
  61. "third_openid"=>$signData["open_id"],
  62. )
  63. )
  64. ->orderBy("id","desc")->first();
  65. try {
  66. DB::beginTransaction();
  67. $plaintext = "";
  68. $defaultPassword = "";
  69. if (!empty($checkUserData)){
  70. $plaintext = "{$checkUserData->username}@123456";
  71. $defaultPassword = bcrypt($plaintext);
  72. }
  73. if (empty($checkUserData)){
  74. //开始菜单授权
  75. $permissionModelClass = config('admin.database.permissions_model');
  76. $roleModelClass = config('admin.database.roles_model');
  77. $userAvatar = config('admin.default_avatar');
  78. $name = "";//名称
  79. $userName="";//登录账号
  80. $userData = $this->getUserData($signData["open_id"]);//下面需要获取用户账号、昵称、头像
  81. if (isset($userData["user"])){
  82. if (isset($userData["user"]["name"])){
  83. $name = $userData["user"]["name"];
  84. }
  85. $name = empty($name)?$userData["user"]["username"]:$name;
  86. $userName = $userData["user"]["username"];
  87. }
  88. $plaintext = "{$userName}@123456";
  89. $defaultPassword = bcrypt($plaintext);
  90. $checkUserData = $userModel->create(array(
  91. "username"=>$userName,
  92. "password"=>$defaultPassword,
  93. "name"=>$name,
  94. "avatar"=>null,
  95. ));
  96. if (empty($checkUserData)){
  97. throw new \RuntimeException("新增用户信息失败");
  98. }
  99. DB::table($userModel::query()->getModel()->getTable())->where(
  100. array("id"=>$checkUserData->id)
  101. )->update(array(
  102. "third_openid"=>$signData["open_id"],
  103. "workstation_id"=>$paramsData['outside_c_id'],
  104. "workstation_name"=>$paramsData['visit_title']
  105. ));
  106. $roleSlugName = array("RemoteSso");//角色名称 slug
  107. $permissionsSlugName = array("RemoteSso");//权限名称 slug
  108. $permissionModel = new $permissionModelClass();
  109. $roleModel = new $roleModelClass();
  110. foreach ($roleSlugName as $val){
  111. $roleData = $roleModel::query()
  112. ->where(
  113. array(
  114. "slug"=>$val
  115. )
  116. )
  117. ->orderBy("id","desc")->first();
  118. if (!empty($roleData)){
  119. DB::table("admin_role_users")->insert(
  120. array(
  121. "role_id"=>$roleData->id,
  122. "user_id"=>$checkUserData->id,
  123. "created_at"=>date("Y-m-d H:i:s")
  124. )
  125. );
  126. }
  127. }
  128. foreach ($permissionsSlugName as $val){
  129. $permissionData = $permissionModel::query()
  130. ->where(
  131. array(
  132. "slug"=>$val
  133. )
  134. )
  135. ->orderBy("id","desc")->first();
  136. if (!empty($permissionData)){
  137. DB::table("admin_user_permissions")->insert(
  138. array(
  139. "permission_id"=>$permissionData->id,
  140. "user_id"=>$checkUserData->id,
  141. "created_at"=>date("Y-m-d H:i:s")
  142. )
  143. );
  144. }
  145. }
  146. }
  147. DB::commit();
  148. Admin::guard()->login(
  149. $checkUserData
  150. );
  151. auth('admin')->login(
  152. $checkUserData
  153. );
  154. // echo 'aaaaaaa';exit;
  155. $key = "RemoteSso:".$_SERVER['HTTP_HOST'].":".$checkUserData->id;
  156. Redis::SET($key, true);
  157. $goUrl = $signData['go_url'] ?: $this->url;
  158. // Log::info("登录成功",[$checkUserData->id,$checkUserData->username, $goUrl]);
  159. return $next($request);
  160. }catch (\Exception $exception){
  161. // Log::error("远程授权登录出错",[$exception->getMessage(),$exception->getTrace()]);
  162. DB::rollBack();
  163. return "登录失败";
  164. }
  165. }
  166. public function getUserData(string $openId)
  167. {
  168. if (empty($openId)){
  169. throw new \Exception("openId不能为空");
  170. }
  171. $config = config("console.remote_sso");
  172. $url = $config["url"].self::USER_DATA_URL;//http://www.baidu.com/api.php
  173. $query = array(
  174. "op"=>"user",
  175. "task"=>"userData",
  176. "version"=>"1.0.0",
  177. "appid"=>$config["appid"]
  178. );
  179. $sendData = array(
  180. "open_id"=>$openId
  181. );
  182. $postData = $sendData;
  183. $query["sign"] = $this->getSign($postData,$query["op"],$query["task"],$query["version"]);
  184. // $client = new Client();
  185. $url = $url."?".http_build_query($query);
  186. $resultStr = $this->curlPost($url,$postData);
  187. // $response = $client->request('post', $url, [
  188. // 'query' => $query,
  189. // "headers"=>array(
  190. // "Content-type"=>"application/json"
  191. // ),
  192. // "form_params"=>$postData
  193. // ]);
  194. // $resultStr = $response->getBody()->getContents();
  195. return $this->getResult($resultStr);
  196. }
  197. public function getSign(array $sendData, string $op = "user", string $task = "login", string $version = "1.0.0")
  198. {
  199. $config = config("console.remote_sso");
  200. $appid = $config["appid"];
  201. $secret = $config["secret"];
  202. ksort($sendData);
  203. $str = "";
  204. foreach($sendData as $key =>$value){
  205. $str.= stripslashes($value);
  206. }
  207. $sign = md5($appid. $op . $task . $version . $str. $secret);
  208. return $sign;
  209. }
  210. public function getSsoSign(array $data)
  211. {
  212. $config = config("console.remote_sso");
  213. $appid = $config["appid"];
  214. $secret = $config["secret"];
  215. ksort($sendData);
  216. $str = "";
  217. foreach($sendData as $key =>$value){
  218. $str.= stripslashes($value);
  219. }
  220. $sign = md5($appid. $str. $secret);
  221. return $sign;
  222. }
  223. /**
  224. * 得到结果数据
  225. * @param string $resultStr
  226. * @return mixed
  227. * @throws \Exception
  228. */
  229. private function getResult(string $resultStr){
  230. $result = json_decode($resultStr,true);
  231. if (json_last_error() !== JSON_ERROR_NONE) {
  232. // $this->log("数据格式响应错误",$resultStr);
  233. throw new \Exception("数据格式响应错误".$resultStr);
  234. }
  235. if (empty($result["status"])){
  236. $content = $result["message"] ?? $resultStr;
  237. // $this->log("结果信息发生错误",$content);
  238. throw new \Exception("结果信息发生错误".$content);
  239. }
  240. if (!isset($result["data"])){
  241. $content = $resultStr;
  242. // $this->log("结果信息格式发送错误",$content);
  243. throw new \Exception("结果信息格式发送错误".$content);
  244. }
  245. return $result["data"];
  246. }
  247. private function curlPost($url, $data=null, $file=null)
  248. {
  249. $ch = curl_init($url);
  250. curl_setopt($ch, CURLOPT_TIMEOUT, 60); //设置超时
  251. // if(!empty($file)){
  252. // foreach ($file as $k=>$v){
  253. // if(is_array($v)){
  254. // //多个文件
  255. // foreach ($v as $key=>$val){
  256. // $data[$k.'['.$key.']'] = new CURLFile($val);
  257. // }
  258. // }else{
  259. // //一维
  260. // $data[$k] = new CURLFile($v);
  261. // }
  262. // }
  263. // }
  264. if (0 === strpos(strtolower($url), "https")) {
  265. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //对认证证书来源的检查
  266. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); //从证书中检查SSL加密算法是否存在
  267. }
  268. curl_setopt($ch, CURLOPT_POST, true);
  269. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  270. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  271. // curl_setopt($ch, CURLOPT_HTTPHEADER);
  272. $rtn = curl_exec($ch);//CURLOPT_RETURNTRANSFER 不设置 curl_exec返回TRUE 设置 curl_exec返回json(此处) 失败都返回FALSE
  273. curl_close($ch);
  274. return $rtn;
  275. }
  276. /**
  277. * json 形式传参
  278. * @param unknown $url
  279. * @param unknown $data
  280. */
  281. private function curlPostJson($url, $data = null)
  282. {
  283. $headers = array(
  284. "Content-type: application/json;charset='utf-8'",
  285. "Accept: application/json",
  286. "Cache-Control: no-cache",
  287. "Pragma: no-cache",
  288. );
  289. $ch = curl_init($url);
  290. curl_setopt($ch, CURLOPT_TIMEOUT, 60); //设置超时
  291. if (0 === strpos(strtolower($url), "https")) {
  292. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //对认证证书来源的检查
  293. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); //从证书中检查SSL加密算法是否存在
  294. }
  295. curl_setopt($ch, CURLOPT_POST, true);
  296. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  297. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  298. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  299. curl_setopt($ch, CURLOPT_HEADER, 1);//打印响应header
  300. $rtn = curl_exec($ch);//CURLOPT_RETURNTRANSFER 不设置 curl_exec返回TRUE 设置 curl_exec返回json(此处) 失败都返回FALSE
  301. $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
  302. // 根据头大小去获取头信息内容
  303. $header = substr($rtn, 0, $header_size);
  304. $data = substr($rtn, $header_size);
  305. $is_gzipped = false;
  306. if (preg_match("/Content-Encoding: gzip/", $header)) {
  307. $is_gzipped = true;
  308. }
  309. if($is_gzipped){
  310. $data = gzdecode($data);
  311. }
  312. curl_close($ch);
  313. return $data;
  314. }
  315. }