Задать вопрос
  • Каковы основные принципы регистрации и авторизации через социальные сети OAuth2?

    hbuser
    @hbuser Автор вопроса
    Отвечу сам себе.
    Здесь есть полезная конкретная информация о технической реализации.

    А если вкратце, то...

    Для авторизации, регистрации используется все та же таблица 'users'. Вместе с обычной регистрацией и авторизацией, когда при регистрации (в самом простом виде) в таблицу 'users' добавляются email, password и login пользователя, а при авторизации проверяется соответствие введенных login'а и password'а существующим в базе данных, аналогичным образом используется и регистрация/авторизация через социальные сети. Только в данном случае источником данных о пользователе для его регистрации является не непосредственный пользователь, который вводит данные в форму, а соц. сеть. Регистрация в данном случае достаточно прозрачная, т.е. не видна пользователю. Схема примерно следующая (без особенностей работы Oauth-протокола):


    1) Пользователь выбирает вход через соц. сеть.
    2) Происходит обращение к странице авторизации в этой соц. сети, если человек еще не авторизовывался там. После ввода данных, а если он ранее авторизовывался, происходит запрос на разрешение использования его данных.
    3) Если человек отказывается, то на этом конец. Если дает согласие, то выполняется перенаправление на указанную в настройках Oauth страницу сайта.
    4) У каждого пользователя в соц. сетях есть свой уникальный идентификатор, который можно запрашивать. Для своей таблицы 'users' нужно добавить пару дополнительных полей (например, вот такие): auth_via (enum('native, 'vk', 'mailru', '...')) - для обозначения типа регистрации пользователя, и social_id - здесь будет храниться уникальный идентификатор в соц. сети. Если нужно хранить какие-то специфические данные этого пользователя из соц. сетей, то можно создать доп. поля для этих данных.
    5) После того, как пользователь дал разрешение на использование его данных, необходимо запросить нужные данные от соц. сети, в т.ч. и идентификатор пользователя в соц. сети. Вот здесь и начинается невидимый процесс регистрации. Нужно проверить есть ли в БД пользователь с таким social_id, если нет, то вставляем social_id, данные пользователя из соц. сети, по необходимости, в БД. Все, пользователь зарегистрирован.
    Если же данные о пользователе есть, то необходимо запросить актуальные данные из соц. сети, сравнить их с теми, что в базе и если они изменились, то обновить их и в своей базе данных, если нет, то просто переходим к следующему шагу.
    6) Создается сессия с данными пользователя.

    Таким образом, к существующей таблице "родной" регистрации пользователей сайта присоединяется, условно говоря, таблица, поля, необходимые для регистрации/авторизации через соц. сети., и друг-другу они не мешают.

    ca4a4b263fd1424085988c9deaeb6d5b.png

    Для пользователя, зарегистрированного из соц. сети пароля и логина, естественно, нет. Они нужны для авторизации. А т.к. пользователь авторизуется с помощью своих логина и пароля в соц. сети, то и указывать здесь нечего. И еще, можно при авторизации, к запросу проверки логина и пароля, добавить условие

    'AND WHERE `auth_via`="native"'

    , чтобы исключить пользователей, зарегистрированных из соц. сетей.

    Как видно, для каждого пользователя в таблице создается внутренний (внутрисайтовый, если так можно выразиться) первичный, автоинкрементный ключ. Соответственно, нет разницы для логики сайта между пользователем, зарегистрированным через соц. сеть и через сайт. Если говорить об интернет-магазине, то, для привязки заказов к пользователю, можно использовать единый, внутренний идентификатор ID.
    Ответ написан
    3 комментария
  • Как сделать такой "прогерссбар" при скроллинге?

    Fzero0
    @Fzero0
    Вечный студент
    Комментировать
  • Как засунуть текст в border-bottom?

    NikolayAlb
    @NikolayAlb
    ::after + position: absolute + background: white
    Ответ написан
    Комментировать
  • Как верно организовать роутинг для блога?

    dmitriylanets
    @dmitriylanets
    веб-разработчик
    //config/routes.php
    $route[':any/(:any)/(\d+)'] = "startup/subcategory/$1/$2";
    $route[':any/(:any)/(:any)'] = "startup/subcategory_post/$1/$2";
    
    $route['(:any)/(\d+)'] = "startup/category/$1/$2";
    $route[':any/(:any)'] = "startup/category_post/$1";


    //controllers/startup.php
    class Startup extends CI_Controller{
    
        public function category_post($post)
        {
            echo 'category_post '.$post;
        }
        
        public function category($cat,$page)
        {
            echo 'category '.$cat.' '.$page;
        }
        public function subcategory_post($subcat,$post)
        {
            echo 'subcategory_post '.$subcat.' '.$post;
        }      
        public function subcategory($cat,$page)
        {
            echo 'subcategory '.$cat.' '.$page;
        }
    }
    Ответ написан
    3 комментария
  • Минимальные настройки безопасности Linux на VPS?

    Tyranron
    @Tyranron
    Ряд моментов Вы уже сделали, но я все равно их опишу для полноты списка.

    1. Создать отдельного пользователя и хороший пароль на sudo. Не использовать больше root напрямую. Совсем.

    2. SSH. Отключаем метод аутентификации по паролю. Если Вам не нужны другие методы, то их тоже можно отключить, оставив только publickey. Отключаем возможность аутентификации root'ом. Включаем использование только 2й версии SSH протокола.

    3. Устанавливаем Fail2Ban и настраиваем чтобы после нескольких неуспешных попыток подключения по SSH банило по IP на длительное время. Кол-во попыток и время бана можно тюнить в меру своей паранойи. У меня, например, банит на час после 2х неуспешных попыток.

    4. Iptables. Действуем по принципу "запрещено все, что не разрешено". Запрещаем по умолчанию весь INPUT и FORWARD трафик снаружи. Открываем на INPUT'е 22 порт. В дальнейшем открываем порты/forwarding по мере необходимости. Если у нас предполагаются сервисы на соседних серверах нужные только для внутренней коммуникации (Memcached, Redis, и т.д.), то открываем для них порты только для определенных IP. Просто так торчать наружу для всех они не должны.

    5. Настраиваем автоматические обновления apt-пакетов. Уровень security. То есть так, чтобы обновления безопасности накатывались автоматически, но при этом не выполнялись обновления со сменой мажорной версии (дабы обезопасить себя от "само сломалось").

    6. Устанавливаем ntpd. Серверное время должно быть точным. Также временную зону сервера лучше всего установить в UTC.

    7. TLS (не SSL) используем везде где можем. Через Let's Encrypt получаем бесплатные валидные сертификаты. В конфигах веб-серверов, mail-серверов, и других приложений торчащих наружу (в том числе и OpenVPN), запрещаем/убираем использование слабых шифров. Все ключи/параметры генерируем не менее 2048 бит. Самоподписные сертификаты подписываем с помощью SHA-256 (не SHA-1). Diffie-Hellman параметры (dh.pem) под каждый сервис лучше сгенерить отдельно. Проверяем TLS сервисов через Nmap. Минимальный grade должен быть A, не должно быть warning'ов.

    8. Правильный менеджмент пользователей/групп. Приложения/сервисы не должны запускаться под root'ом (разве что они действительно этого требуют и иначе никак). Для каждого сервиса создается свой пользователь.

    9. Если предполагается upload файлов через PHP (либо другие скриптовые языки), в директории, куда эти файлы загружаются (и которая доступна снаружи), должно быть жестко отключено любое выполнение скриптов/бинарников, что на уровне ОС (x права), что на уровне веб-сервера.

    Это была база.
    Дальше, в меру своей паранойи можно за'harden'ить сервер ещё следующими моментами:
    - SELinux, chroot
    - доступ к SSH только с определенных IP (нужно иметь 3-4 VPN-сервера под рукой)

    UPD И да, все это помнить/настраивать руками каждый раз может быть запарно. Используйте Ansible и автоматизируйте процесс (там родные и YAML, Jinja2 и Python).
    Ответ написан
    10 комментариев
  • Как настроить зеркало сайта на Vesta Panel?

    DarWiM
    @DarWiM
    Скорее всего уже не актуально, но кому-то может быть полезно.

    Если я правильно понял вопрос, то это решается добавлением алиасов домена в разделе WEB.

    UP
    А если нужен разный robots.txt для разных доменов, то в случае с NGINX это делается примерно так
    server {
    ...
        server_name domain1.ru domain2.ru;
    ...
        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
    	alias /home/username/web/domain1.ru/public_html/robots/$host.txt; 
        }
    ...
    }


    Естественно нужно сделать новый шаблон NGINX в VestaCP и назначить его на домен.
    Ответ написан
    5 комментариев
  • Резиновое видео?

    xmoonlight
    @xmoonlight
    https://sitecoder.blogspot.com
    <style>
    *{margin:0;padding:0;}
    iframe {border:0}
    .iframebox {
        width: 100vw;
        height: 70vw;
    }
    @media screen and (min-aspect-ratio: 10/7) {
    	.iframebox {
    		width: 142.8571428571429vh;
    		height: 100vh;
    	}
    }
    </style>
    <iframe class="iframebox" src="https://www.youtube.com/embed/9G-eLuTuwqc"></iframe>
    Ответ написан
    3 комментария
  • Как в JQUERY найти чекбокс по id и проверить его атрибут cheked?

    ewgenio
    @ewgenio
    Всё по чуть чуть
    $('#big').prop('checked');
    Ответ написан
    Комментировать
  • Как переделать фильтр (нужен пример) по произвольным полям wp через get_posts?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    https://codex.wordpress.org/Class_Reference/WP_Query
    https://codex.wordpress.org/Class_Reference/WP_Que...

    UPDATE:

    1. Создаем выпадающий список для фильтра со всеми уникальными значениями "брендов" (в соответствующем шаблоне - над Loop с постами, перед if( have_posts() ) ):
    <?php
    // Получаем все уникальные значения брендов
    $brands = $wpdb->get_col(
    	"SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = 'brand'"
    );
    
    // Если бренды есть - строим блок с фильтром
    if ( $brands ) : 
    ?>
    
    <div class="filter">
    	<span>Filter by brand:</span>
    	<select name="brand" id="brand">
    		<!-- Сброс фильтра в значение "все" (оно же по умолчанию)  -->
    		<option value="All" 
    				<?php echo ( empty( $_GET['brand'] ) || 'All' === $_GET['brand'] ) ? 'selected="selected"' : ''; ?>
    		>All</option>
    		<!-- Все бренды -->
    		<?php foreach ( $brands as $brand ) : ?>
    			<option value="<?php echo esc_html( $brand ); ?>" 
    					<?php echo ( ! empty( $_GET['brand'] ) && $brand === $_GET['brand'] ) ? 'selected="selected"' : ''; ?>
    			><?php echo esc_html( $brand ); ?></option>
    		<?php endforeach; ?>
    	</select>
    </div>
    
    <script>
    jQuery('#brand').on('change', function(){
    	window.location.href =  '<?php echo get_nopaging_url(); ?>' + '?brand=' + jQuery(this).val();
    });
    </script>
    <?php endif; ?>

    Конечно, этот кусочек javascript лучше перенести в свой файл скриптов, который подгружается через wp_enqueue_scripts(), данный пример для наглядности.

    2. Хукаемся в основной запрос перед его выполнением, отлавливаем переменную и модифицируем запрос (это в functions.php):
    /**
     * Меняем основной запрос по необходимости, непосредственно перед его выполнением, сохраняя все фичи (включая пагинацию)
     */
    function my_filter_posts( $query ) {
    
    	// Если это не главный запрос или админка - прекращаем выполнение
    	if( ! $query->is_main_query() || is_admin() ) {
    		return;
    	}
    
    	// Если есть GET-параметр brand с не пустым значением и оно не равно All - модифицируем запрос
    	if( ! empty( $_GET['brand'] ) && 'All' != $_GET['brand'] ) {
    		$query->set( 'meta_key', 'brand' );
    		$query->set( 'meta_value', sanitize_text_field( $_GET['brand'] ) );
    	}
    
    }
    add_action( 'pre_get_posts', 'my_filter_posts' );

    3. И еще нам понадобится утилитарная функция get_nopaging_url() которую мы использовали в js (добавляем ее тоже в functions.php):
    /**
     * Get current URL without /page/{pagenum}/ part if it's present
     */
    function get_nopaging_url() {
    
    	global $wp;
    
    	$current_url =  home_url( $wp->request );
    	$position = strpos( $current_url , '/page' );
    	$nopaging_url = ( $position ) ? substr( $current_url, 0, $position ) : $current_url;
    
    	return trailingslashit( $nopaging_url );
    
    }
    Ответ написан
    21 комментарий
  • Как добавить кнопку в меню wordpress?

    streetflush
    @streetflush
    Если сделана через wordpress, папробуйте плагин найти для ниго.
    Ответ написан
    Комментировать
  • Как в input передать значение data-*?

    webinar
    @webinar
    Учим yii: https://youtu.be/-WRMlGHLgRg
    $('a.someclass').on('click',function(){
    var mysuperdata = $(this).attr('data-product');
    $('input#someuniqid').val(mysuperdata);
    alert("ох ты ж епт");
    });
    Ответ написан
    4 комментария
  • Как избавиться от ERR_TOO_MANY_REDIRECTS при переносе сайта с HTTP на HTTPS на Wordpress?

    Punkie
    @Punkie
    Была точно такая же проблема у меня.

    Добавьте в wp-config.php в самое начало (после <?php ):

    $_SERVER['HTTPS'] = 'on';

    Плюс пониже после define всяких (до текста "/* Это всё, дальше не редактируем. Успехов! */"):

    define('FORCE_SSL_ADMIN', true);
    define('FORCE_SSL_LOGIN', true);
    if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
           $_SERVER['HTTPS']='on';


    Если будут проблемы с путями у картинок, поставьте этот плагин:
    https://wordpress.org/plugins/velvet-blues-update-urls/

    И замените http://ваш_домен на https://ваш_домен с его помощью
    Ответ написан
    14 комментариев
  • Есть ли способ включить поддержку https в wordpress без плагинов?

    mercury4
    @mercury4 Автор вопроса
    Итоговый алгоритм для меня получился таким:
    1. указываю в настройках путей протокол
    2. в wp-config.php добавляю $_SERVER['HTTPS']='on';
    3. чищу куки.
    Ответ написан
    Комментировать
  • Как правильно сверстать адаптивный слайдер?

    abyrkov
    @abyrkov
    JavaScripter
    width: calc(100% - 50px);
    Аналогичным образом я верстаю любую адапцию без js.
    Ответ написан
    Комментировать
  • Как настроить https:// в wordpress?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    В wp-config
    define('FORCE_SSL_ADMIN', true);
    if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
           $_SERVER['HTTPS']='on';
    Ответ написан
    2 комментария
  • Как сформировать архитектуру в фреймворке?

    @AlexanderWalker
    И лучше этот код вынести в отдельную библиотеку и вызывать функцию передавая ей параметры
    $headData['title'] = "";
    $headData['keywords'] = "";
    $headData['seo_description'] = "";
    $headData['scripts'] = array(); // Массив скриптов. Потом во фронте циклом их выгрузить
    $headData['styles'] = array(); // Массив стилей. Аналогично выгружать
    
    $data['header'] =  $this->CI->load->view('template/header' , $headData , true); //Шапка
    $data['footer'] =  $this->CI->load->view('template/footer' , array() , true); //Футер
    $pageData['pageContent'] = array(); // Какой-то контент для страницы
    $data['content'] = $this->CI->load->view('front/*your-page*' , $pageData , true); //Страницу которую грузить в шаблон
    $this->load->view('template/'.$template , $data  ); //В какой шаблон грузить страницу
    Ответ написан
    Комментировать
  • Как выполнить PHP функцию до генерации страницы Wordpress'ом?

    MetaDone
    @MetaDone
    Хорошо сформулированный вопрос - 50% решения
    add_action("init",function(){
    //здесь то, что нужно сделать
    });

    вписываете в functions.php вашей темы. можете погуглить порядок срабатывания событий в вордпрессе, init - самое первое
    Ответ написан
    Комментировать