Kaynağa Gözat

feat:language captcha

igb 4 ay önce
ebeveyn
işleme
27e6e210e7

+ 82 - 0
app/Admin/Controllers/AuthController.php

@@ -2,14 +2,95 @@
 
 namespace App\Admin\Controllers;
 
+use App\Models\DistAdminDistributor;
+use Dcat\Admin\Admin;
 use Dcat\Admin\Form;
 use Dcat\Admin\Http\Controllers\AuthController as BaseAuthController;
 use Dcat\Admin\Http\Repositories\Administrator;
+use Dcat\Admin\Layout\Content;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Session;
+use Illuminate\Support\Facades\Validator;
 
 class AuthController extends BaseAuthController
 {
     protected $view = 'admin.pages.login';
 
+    /**
+     * Login interface.重写登录接口
+     * @param Request $request
+     * @return
+     */
+    public function postLogin(Request $request)
+    {
+
+        $credentials = $request->only([$this->username(), 'password', 'captcha']);
+        $remember = (bool)$request->input('remember', false);
+
+        /** @var \Illuminate\Validation\Validator $validator */
+        $validator = Validator::make($credentials, [
+            $this->username() => 'required',
+            'password' => 'required',
+            'captcha' => 'required',
+        ]);
+
+
+        if ($request->input('captcha') != Session::get('captcha'))
+        {
+            $session_captcha = Session::get('captcha');
+
+            //Session::forget('captcha');
+            return response()->json([
+                'success' => false,
+                'message' => 'The captcha['.$session_captcha.'] is incorrect. Please refresh the page and try again.',
+                'refresh_captcha' => true, // 通知前端刷新验证码
+            ], 422);; // 422 表示 Unprocessable Entity
+        }
+        else
+        {
+            //Session::forget('captcha');
+        }
+
+
+        unset($credentials['captcha']);
+
+        if ($validator->fails()) {
+            return $this->validationErrorsResponse($validator);
+        }
+
+        if ($this->guard()->attempt($credentials, $remember)) {
+
+            // 登录成功后返回登录响应
+            return $this->sendLoginResponse($request);
+        }
+
+        return $this->validationErrorsResponse([
+            $this->username() => $this->getFailedLoginMessage(),
+        ]);
+    }
+
+    /**
+     * 重写登录控制器
+     * @param Content $content
+     * @return Content
+     */
+    function getLogin(Content $content)
+    {
+        $lang = request()->query('lang');
+
+        if(!empty($lang))
+        {
+            switchLanguage($lang);
+            return response()->json(['success' => true, 'lang' => $lang]);
+        }
+
+        if ($this->guard()->check()) {
+            return redirect($this->getRedirectPath());
+        }
+
+        return $content->full()->body(view($this->view));
+    }
+
     /**
      * Model-form for user setting.
      *
@@ -77,4 +158,5 @@ class AuthController extends BaseAuthController
     }
 
 
+
 }

+ 92 - 0
app/Admin/Controllers/CaptchaController.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use Dcat\Admin\Http\Controllers\AdminController;
+use Illuminate\Support\Facades\Session;
+
+class CaptchaController extends AdminController
+{
+
+    public function generate()
+    {
+
+        // 生成验证码字符串
+        $characters = '23456789';
+        $captchaString = '';
+
+        for ($i = 0; $i < 6; $i++) {
+            $captchaString .= $characters[rand(0, strlen($characters) - 1)];
+        }
+
+
+        // 创建图片
+        $width = 120;
+        $height = 40;
+        $image = imagecreate($width, $height);
+
+        // 定义颜色
+        $backgroundColor = imagecolorallocate($image, 243, 243, 243); // 背景色(浅灰色)
+        $textColor = imagecolorallocate($image, 51, 51, 51); // 文本颜色(深灰色)
+        $lineColor = imagecolorallocate($image, 204, 204, 204); // 干扰线颜色(浅灰色)
+
+        // 添加干扰线(每条线的颜色随机)
+        for ($i = 0; $i < 5; $i++) {
+            $lineColor = imagecolorallocate(
+                $image,
+                rand(0, 255), // 随机红色分量
+                rand(0, 255), // 随机绿色分量
+                rand(0, 255)  // 随机蓝色分量
+            );
+
+            imageline(
+                $image,
+                rand(0, $width),
+                rand(0, $height),
+                rand(0, $width),
+                rand(0, $height),
+                $lineColor
+            );
+        }
+
+        // 添加验证码文本
+        $fontSize = 5; // 字体大小,GD 内置字体大小范围是 1 到 5
+        $xOffset = 10; // 起始 X 偏移
+
+        for ($i = 0; $i < strlen($captchaString); $i++) {
+            $textColor = imagecolorallocate(
+                $image,
+                rand(0, 150), // 随机红色分量
+                rand(0, 150), // 随机绿色分量
+                rand(0, 150)  // 随机蓝色分量
+            );
+
+            // 随机调整每个字符的位置
+            $x = $xOffset + ($i * 15) + rand(-2, 2); // 每个字符的水平位置随机微调
+            $y = rand(10, $height - imagefontheight($fontSize)); // 垂直位置随机
+
+            imagestring(
+                $image,
+                $fontSize,
+                $x,
+                $y,
+                $captchaString[$i],
+                $textColor
+            );
+        }
+
+        // 存储验证码文本到会话
+        Session::put('captcha', $captchaString);
+
+        // 输出图片
+        ob_start();
+        imagepng($image);
+        $imageData = ob_get_clean();
+
+        // 释放内存
+        imagedestroy($image);
+
+        return response($imageData)->header('Content-Type', 'image/png');
+    }
+}
+

+ 9 - 13
app/Admin/Controllers/LanguageController.php

@@ -11,6 +11,7 @@ class LanguageController extends Controller
         return $this->switchLanguage($request);
     }
 
+
     /**
      * 切换语言并修改 app.locale
      *
@@ -19,24 +20,19 @@ class LanguageController extends Controller
      */
     public function switchLanguage(Request $request)
     {
+
         // 从 URL 参数中获取语言,默认为 'en'
         $lang = $request->input('lang', 'en');
 
+        if (!$lang)
+        {
+            abort(404);
+        }
         // 验证是否是支持的语言
         if (!in_array($lang, ['en', 'zh_CN'])) {
-            return redirect()->back()->withErrors(['error' => '不支持的语言']);
+            abort(404);
         }
-
-        $configArray = ['lang' => $lang,];
-
-        user_admin_config($configArray);
-
-        // 动态修改 app.locale 配置
-        config(['app.locale' => $lang]);
-
-//        // 返回重定向或其他操作
-//        return redirect()->back()->with('success', '语言已切换为: ' . $lang);
-        return redirect('/prime-control');
+        switchLanguage($lang);
+        return response()->json(['success' => true, 'lang' => $lang]);
     }
-
 }

+ 6 - 0
app/Admin/routes.php

@@ -39,6 +39,12 @@ Route::group([
     $router->any('dist-template/ace', [DistAppearanceTemplateController::class, 'ace']);
     //模板变量
     $router->resource('dist-template-var', 'DistAppearanceVariableController');
+
+    // 定义切换语言的路由
+    $router->get('language-switch','LanguageController@index');
+
+    // 不需要登录的路由
+    $router->get('captcha','CaptchaController@generate');
 });
 
 /*

+ 2 - 1
config/admin.php

@@ -165,6 +165,7 @@ return [
         'except' => [
             'auth/login',
             'auth/logout',
+            'captcha',
         ],
 
         'enable_session_middleware' => false,
@@ -230,7 +231,7 @@ return [
             '/',
             'auth/login',
             'auth/logout',
-            'auth/setting',
+            'auth/setting'
         ],
     ],
 

+ 66 - 0
resources/views/admin/pages/login.blade.php

@@ -89,6 +89,34 @@
                         @endif
 
                     </fieldset>
+                    <fieldset class="form-label-group form-group position-relative has-icon-left">
+                        <input
+                            minlength="6"
+                            maxlength="6"
+                            id="captcha"
+                            type="captcha"
+                            class="form-control"
+                            name="captcha"
+                            placeholder="{{ trans('admin.captcha') }}"
+                            required
+                        >
+
+                        <div class="form-control-position">
+                            <i class="feather icon-image"></i>
+                        </div>
+                        <label for="captcha">{{ trans('admin.captcha') }}</label>
+
+                        <div class="help-block with-errors"></div>
+                        @if($errors->has('captcha'))
+                            <span class="invalid-feedback text-danger" role="alert">
+                                            @foreach($errors->get('captcha') as $message)
+                                    <span class="control-label" for="inputError"><i class="feather icon-x-circle"></i> {{$message}}</span><br>
+                                @endforeach
+                            </span>
+                        @endif
+                        <img src="/prime-control/captcha?{{ time() }}" alt="captcha" class="captcha-img" onclick="this.src='/prime-control/captcha?'+Math.random()">
+                    </fieldset>
+
                     <div class="form-group d-flex justify-content-between align-items-center">
                         <div class="text-left">
                             @if(config('admin.auth.remember'))
@@ -106,6 +134,13 @@
                             @endif
                         </div>
                     </div>
+                    <div class="form-group d-flex justify-content-between align-items-center">
+                        <div class="text-left">
+                            <a class="lang-item" href="javascript:void(0);" data-lang="en">English</a>
+                            <a class="lang-item" href="javascript:void(0);" data-lang="zh_CN">中文</a>
+                        </div>
+                    </div>
+
                     <button type="submit" class="btn btn-primary float-right login-btn">
 
                         {{ __('admin.login') }}
@@ -127,3 +162,34 @@ Dcat.ready(function () {
     });
 });
 </script>
+<script>
+    document.querySelectorAll('.lang-item').forEach(item => {
+        item.addEventListener('click', function() {
+            const lang = this.getAttribute('data-lang');
+            switchLanguage(lang);
+        });
+    });
+
+    function switchLanguage(lang) {
+        fetch(`/prime-control/auth/login?lang=${encodeURIComponent(lang)}`, {
+            method: 'GET'
+        })
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error('Network response was not ok');
+                }
+                return response.json();
+            })
+            .then(data => {
+                if (data.success) {
+                    window.location.reload();
+                } else {
+                    throw new Error(data.error || 'Language switch failed');
+                }
+            })
+            .catch(error => {
+                console.error('Language Switch Error:', error);
+                alert('Failed to switch language. Please try again.');
+            });
+    }
+</script>

+ 42 - 0
resources/views/admin/partials/navbar.blade.php

@@ -48,6 +48,11 @@
                     <a href="javascript:;"  data-check-screen="full" class="nav-link"><i class="feather icon-maximize f16"></i></a>
                     @endif
                     -->
+
+                    <i class="fa fa-language f16"></i>
+                    <a class="lang-item " href="javascript:void(0);" data-lang="en">English</a>
+                    <a class="lang-item " href="javascript:void(0);" data-lang="zh_CN">中文</a>
+
                     <ul class="nav navbar-nav">
                         {{--User Account Menu--}}
                         {!! admin_section(Dcat\Admin\Admin::SECTION['NAVBAR_USER_PANEL']) !!}
@@ -61,3 +66,40 @@
 </nav>
 @endif
 {!! admin_section(Dcat\Admin\Admin::SECTION['NAVBAR_AFTER']) !!}
+
+<style>
+    .lang-item {
+        margin-left: 0.5rem;
+    }
+</style>
+<script>
+    document.querySelectorAll('.lang-item').forEach(item => {
+        item.addEventListener('click', function() {
+            const lang = this.getAttribute('data-lang');
+            switchLanguage(lang);
+        });
+    });
+
+    function switchLanguage(lang) {
+        fetch(`/prime-control/language-switch?lang=${encodeURIComponent(lang)}`, {
+            method: 'GET'
+        })
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error('Network response was not ok');
+                }
+                return response.json();
+            })
+            .then(data => {
+                if (data.success) {
+                    window.location.reload();
+                } else {
+                    throw new Error(data.error || 'Language switch failed');
+                }
+            })
+            .catch(error => {
+                console.error('Language Switch Error:', error);
+                alert('Failed to switch language. Please try again.');
+            });
+    }
+</script>

+ 1 - 1
resources/views/distributor/pages/login.blade.php

@@ -172,7 +172,7 @@ Dcat.ready(function () {
     });
 
     function switchLanguage(lang) {
-        fetch(`/dist/auth/login?lang=${encodeURIComponent(lang)}`, {
+        fetch(`/language-switch?lang=${encodeURIComponent(lang)}`, {
             method: 'GET'
         })
             .then(response => {

+ 12 - 9
resources/views/distributor/partials/navbar.blade.php

@@ -53,15 +53,13 @@
                     --->
 
                     <!-- Dropdown Menu -->
-                    <div class="dropdown">
-                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                            <i class="fa fa-language f16"></i> {{trans('admin.language')}}
-                        </a>
-                        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
-                            <a class="dropdown-item lang-item" href="javascript:void(0);" data-lang="en">English</a>
-                            <a class="dropdown-item lang-item" href="javascript:void(0);" data-lang="zh_CN">中文</a>
-                        </div>
-                    </div>
+
+
+                            <i class="fa fa-language f16"></i>
+                            <a class="lang-item " href="javascript:void(0);" data-lang="en">English</a>
+                            <a class="lang-item " href="javascript:void(0);" data-lang="zh_CN">中文</a>
+
+
 
                     <ul class="nav navbar-nav">
                         {{--User Account Menu--}}
@@ -77,6 +75,11 @@
 @endif
 {!! admin_section(Dcat\Admin\Admin::SECTION['NAVBAR_AFTER']) !!}
 
+<style>
+    .lang-item {
+        margin-left: 0.5rem;
+    }
+</style>
 <script>
     document.querySelectorAll('.lang-item').forEach(item => {
         item.addEventListener('click', function() {