В данный момент включает следующие большие модули:
common-security-core
common-security-validate
common-security-browser
common-security-app
Универсальная обработка проверочных кодов. Основана на технологии SpringSecurity. Высокая расширяемость, высокая доступность, простая конфигурация, гибкость, поддержка двух режимов: неразделение интерфейса и сервера (хранение данных в сессии) и разделение интерфейса и сервера (например: разделение веб-интерфейса и сервера или форма приложения, использование redis для хранения данных).
security.properties
.@ComponentScan(basePackages = {"com.chentongwei.security", "ваш пакет"})
Сценарий:
Все наши системы имеют функцию входа в систему, а наиболее распространёнными являются три типа: форма входа, SMS-вход и сторонний вход.
Для формы входа обычно требуется проверочный код, который может быть графическим или числовым. Нам нужно написать интерфейс для генерации кода и некоторые суждения для проверки правильности. Для SMS-входа нам также необходимо проверить, соответствует ли код SMS ожидаемому. Также есть проблема безопасности URL, например, я не знаю ваш пароль, но я знаю ваш URL доступа, тогда я могу напрямую ввести URL, чтобы перейти на страницу входа.
Проблемы:
Решение
Модуль common-security-validate
может идеально решить все вышеперечисленные проблемы:
code/image
, и возвращаемое значение кодируется в base64. Пример:<img id="imageCode" src="" onclick="getImageCode()" />
window.onload = function () {
getImageCode();
}
function getImageCode() {
$.ajax({
url: "code/image",
type: "get",
/**
* 为什么要在headers里传个deviceId参数?
* 若你是前后端不分离(采取session共享数据),则无需传递此header里的参数。
* 若你是前后端分离(采取redis共享数据),则需要在header里传递deviceId参数,
* 若你是APP,则此参数建议取设备id,若你是web前后分离,则可以从后台获取一个然后放到缓存中,并放到此处。它标记着一个唯一的用户。
*/
headers: {
"deviceId": "123"
},
success: function (data) {
$("#imageCode").attr("src", "data:image/jpeg;base64," + data);
}
});
}
2.1. Сначала зарегистрируйтесь на официальном сайте Geetest и создайте проект, затем получите идентификатор и ключ.
2.2. Затем настройте его в файле конфигурации и вызовите интерфейс code/geetest
, чтобы получить проверочный код Geetest. Пример:
security.properties
:
com.chentongwei.security.code.geetest.id=f4fac365b3ccb82ed68cc8c1ab6346f6
com.chentongwei.security.code.geetest.key=c91ca7c31cf0d8a40c5cf5714624bfb2
com.chentongwei.security.code.geetest.newfailback=true
HTML+JS:
<div class="row cl">
<div id="captcha" class="formControls col-xs-8 col-xs-offset-3">
<p id="wait">正在加载验证码......</p>
</div>
</div>
<button id="popup-submit">测试登录</button>
$.ajax({
// 获取id,challenge,success(是否启用failback)
url: "code/geetest?t=" + (new Date()).getTime(), // 加随机数防止缓存
type: "get",
dataType: "json",
/**
* 为什么要在headers里传个deviceId参数?
* 若你是前后端不分离(采取session共享数据),则无需传递此header里的参数。
* 若你是前后端分离(采取redis共享数据),则需要在header里传递deviceId参数,
* 若你 являешься APP,则 этот параметр рекомендуется взять из deviceId, если ты являешься web передним и задним разделением, то можешь получить его из бэкэнда, сохранить в кэш и передать сюда. Он обозначает уникального пользователя.
*/
headers: {
"deviceId": "123"
},
success: function (data) {
console.log("data:" , data);
// 使用initGeetest接口
// 参数1:配置参数
// 参数2:回调,回调的第一个参数验证码对象,之后可以使用它做appendTo之类的事件
initGeetest({
gt: data.gt,
challenge: data.challenge,
product: "popup", // 产品形式,包括:float,embed,popup。注意只对PC版验证码有效
offline: !data.success // 表示用户后台检测极验服务器是否宕机,与SDK配合,用户一般不需要关注
}, handlerPopup);
}
});
// 代码详细说明
var handlerPopup = function (captchaObj) {
console.info(captchaObj)
// 注册提交按钮事件,比如在登陆页面的登陆按钮
$("#popup-submit").click(function () {
// 此处省略在登陆界面中,获取登陆数据的一些步骤
// 先校验是否点击了验证码
var validate = captchaObj.getValidate();
if (!validate) {
alert('请先完成验证!');
return;
}
// 提交验证码信息,比如登陆页面,你需要提交登陆信息,用户名和密码等登陆数据
$.ajax({
url: "login",
type: "post",
// dataType: "json",
data: {
// 用户名和密码等其他数据,自己获取,不做演示
username:"13123",
password:"123456",
// 验证码数据,这些数据不用自己获取
// 这是二次验证所需的三个值
// 当然,你也可以直接设置验证码单独校验,省略其他信息
geetest_challenge: validate.geetest_challenge, **Текст запроса написан на языке Java.**
Перевод текста запроса на русский язык:
# URL-адрес, требующий перехвата графического проверочного кода
com.chentongwei.security.code.image.url=/login
# URL-адреса, которые требуют перехвата проверочного кода Geetest
com.chentongwei.security.code.geetest.url=/login, /hello
PS: при доступе к указанным выше URL-адресам в нашем конфигурационном файле будет выполнена операция проверки проверочного кода.
Например: мы настроили проверочный код в конфигурации для /login интерфейса входа, прямая передача запроса имени пользователя и пароля для входа в систему будет заблокирована с сообщением об ошибке, указывающим, что проверочный код не может быть пустым и т. д.
Конкретные блокировки включают следующее содержание:
Значение проверочного кода не может быть пустым
Проверочный код не существует, пожалуйста, обновите страницу и повторите попытку
Проверочный код истёк
Проверочный код не совпадает
# URL-адреса без необходимости входа в систему могут быть доступны
com.chentongwei.security.authorize.permitUrls=/hello, /hello2
Графический проверочный код (по умолчанию длина 4, ширина 67, высота 23, срок действия 1 минута)
# Длина графического проверочного кода
com.chentongwei.security.code.image.length=6
# Ширина графического проверочного кода
com.chentongwei.security.code.image.width=150
# Высота графического проверочного кода
com.chentongwei.security.code.image.height=80
# Срок действия графического проверочного кода (с)
com.chentongwei.security.code.image.expireIn=120
# URL-адрес, который требует перехвата графического проверочного кода
com.chentongwei.security.code.image.url=/login
Geetest проверочный код (срок действия по умолчанию 1 минута)
com.chentongwei.security.code.geetest.id=f4fac365b3ccb82ed68cc8c1ab6346f6
com.chentontongwei.security.code.geetest.key=c91ca7c31cf0d8a40c5cf5714624bfb2
com.chentongwei.security.code.geetest.newfailback=true
# Срок действия Geetest проверочного кода (с)
com.chentongwei.security.code.geetest.expireIn=120
# URL-адреса, которые требуют перехвата Geetest проверочного кода
com.chentongwei.security.code.geetest.url=/login, /hello
SMS проверочный код (длина по умолчанию 6, срок действия 1 минута)
# Длина SMS проверочного кода
com.chentongwei.security.code.sms.length=6
# Срок действия SMS проверочного кода
com.chentongwei.security.code.sms.expireIn=120
# URL-адрес, который требует перехвата SMS проверочного кода
com.chentongwei.security.code.sms.url=/mobile
Разделение передней и задней части конфигурации (по умолчанию не разделено, хранилище сеансов)
# redis используется для разделения передней и задней частей, проверочные коды хранятся в redis, по умолчанию не записывается как способ сеанса, передняя и задняя части не разделены.
# Если вы используете метод redis, помните, что в параметрах проверочного кода интерфейса необходимо передать deviceId в заголовке, это подробно описано в демо выше.
com.chentongwei.security.code.repository=redis
Ограничение доступа IP к интерфейсу (по умолчанию доступ к любому интерфейсу не ограничен, если настроен URL-адрес, то по умолчанию можно получить доступ до 10 раз в течение 3 секунд)
# Необходимо установить URL-путь, к которому можно получить доступ с одного и того же IP-адреса несколько раз в определённое время
com.chentongwei.security.authorize.ipValidateUrl=/hello, /hello2
# Настройка времени (в секундах), в течение которого один и тот же IP может получить доступ к одному и тому же URL несколько раз
com.chentongwei.security.authorize.ipValidateSeconds=5
# Настройка количества раз, которое один и тот же IP может получить доступ к одному и тому же URL в течение определённого времени
com.chentongwei.security.authorize.ipValidateCount=5
Конфигурация URL-полномочий
# URL-адреса, которым не требуется вход в систему
com.chentongwei.security.authorize.permitUrls=/hello,/hello2
# Если появляется статус 401, перенаправление на фиксированную страницу
com.chentongwei.security.authorize.unAuthorizePage=/default-login.html
PS:
- По умолчанию все URL заблокированы.
- При попытке доступа к URL без разрешения возвращается статус 401. Если настроена unAuthorizePage, происходит перенаправление на страницу unAuthorizePage. Если unAuthorizePage не настроена, возвращается следующий JSON:
{"code":401,"msg":"Unauthorized","data":null}
REDIRECT / JSON (по умолчанию JSON)
# REDIRECT/JSON после успешной или неудачной аутентификации перенаправляет на страницу или возвращает JSON
com.chentongwei.security.authentication.loginType=REDIRECT
# Способ REDIRECT, страница, на которую перенаправляется после неудачной аутентификации (по умолчанию URL является очень недружелюбным), эта конфигурация JSON недействительна
com.chentongwei.security.authentication.loginErrorPage=http://www.tucaole.cn
# Способ REDIRECT, страница, на которую перенаправляется после успешной аутентификации (по умолчанию это предыдущий URL доступа), эта конфигурация JSON недействительна
com.chentongwei.security.authentication.loginSuccessPage=http://www.tucaole.cn
Графический проверочный код
PS: Если вам не нравится мой сгенерированный графический проверочный код, например, вы считаете, что мои полосы слишком редкие, а стиль слишком уродливый и так далее, вы можете полностью настроить свой собственный проверочный код интерфейса, будьте уверены, даже если это ваш собственный, мой проверочный код всё равно будет работать. Предварительные условия для настройки интерфейса:
- Идентификатор компонента — imageValidateCodeGenerator.
- Реализовать ValidateCodeGenerator com.chentongwei.security.validate.code.ValidateCodeGenerator
@Component("imageValidateCodeGenerator")
public class ImageValidateCodeGenerator implements ValidateCodeGenerator {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public ValidateCode generate(ServletWebRequest request) {
logger.info("Пользовательская логика генерации проверочных кодов...");
*Здесь следует вставить перевод кода.* **Проверка подлинности: генерация и проверка кодов**
return new ValidateCode();
}
}
**Генерация кода проверки подлинности**
> PS:Если вам не нравится сгенерированный код проверки подлинности, вы можете создать собственный интерфейс проверки. Не беспокойтесь, даже если это будет ваш собственный код, моя проверка всё равно будет работать.
> 1. Идентификатор компонента bean должен быть `geetestValidateCodeGenerator`.
> 2. Реализация интерфейса `com.chentongwei.security.validate.code.ValidateCodeGenerator`:
```java
@Component("geetestValidateCodeGenerator")
public class GeetestValidateCodeGenerator implements ValidateCodeGenerator {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public ValidateCode generate(ServletWebRequest request) {
logger.info("Пользовательская логика генерации кода проверки...");
return new ValidateCode();
}
}
СМС-код проверки подлинности
PS: Мой стандартный СМС-код не очень полезен, я просто вывел в консоль строку цифр. Поскольку у разных поставщиков услуг СМС разные методы реализации, я предоставляю интерфейс, который вы можете использовать для подключения к своему поставщику услуг. Не волнуйтесь, даже если вы создадите свой собственный код, моя проверка подлинности всё равно будет работать.
Для создания собственного интерфейса необходимо выполнить следующее:
- Реализовать интерфейс
com.chentongwei.security.validate.code.sms.SmsCodeSender
:
public class MySmsCodeSender implements SmsCodeSender {
@Override
public void send(String mobile, String code) {
System.out.println("send.......");
}
}
Обработка успешной и неудачной аутентификации
PS: Для создания собственной обработки успешной аутентификации необходимо выполнить только одно условие: идентификатор компонента bean должен быть authenticationSuccessHandler.
@Component("authenticationSuccessHandler")
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.info("Аутентификация прошла успешно!");
}
}
PS: Для создания собственной обработки неудачной аутентификации необходимо выполнить только одно условие: идентификатор компонента bean должен быть authenticationFailureHandler.
@Component("authenticationFailureHandler")
public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
logger.info("Ошибка аутентификации!");
}
}
UserDetailsService
Если вы использовали Spring Security, то знаете о UserDetailsService. Я включил DefaultUserDetailsService, но он не имеет практического применения. Единственное его назначение — запуск без ошибок, если не написан пользовательский UserDetailsService. Однако важно написать собственную реализацию UserDetailsService для выполнения логики входа. Моя реализация нужна только для запуска без ошибок!
Основная конфигурация SpringSecurity
Я включил ValidateSecurityCoreConfig, основную конфигурацию, которая содержит некоторые базовые настройки, такие как обработка успеха и неудачи, права доступа к интерфейсу и т. д. Она не включает такие вещи, как сессия, выход из системы и многое другое. Если мои настройки не соответствуют вашим требованиям, вы можете настроить их самостоятельно.
Чтобы настроить SpringSecurity, выполните следующие действия:
# Пользовательская основная конфигурация, false: пользовательская; true: использование моей стандартной конфигурации, значение по умолчанию — true
com.chentongwei.security.core.config.enable=false
Это позволит настроить SpringSecurity.
Рекомендуется включить в него все компоненты, которые были введены в мой класс ValidateSecurityCoreConfig. Вы можете добавить или изменить метод configure, так как в моём классе уже есть введённые компоненты, такие как обработчики успеха и неудачи, валидаторы кода и настройки СМС. Эти функции не нужны? Тогда не используйте этот фреймворк!
Также важно:
@Autowired
private AuthorizeConfigManager authorizeConfigManager;
// Обязательно поместите это в конец, потому что в методе config любые другие методы будут считаться недоступными без аутентификации, а SpringSecurity имеет порядок выполнения.
authorizeConfigManager.config(http);
Если вы не хотите создавать собственный класс конфигурации, можно ли добавить несколько методов HttpSecurity в ваш класс?
Можно, создайте класс, реализующий AuthorizeConfigProvider, и укажите @Order(Integer.MAX_VALUE - 100). Всё остальное не нужно делать. Это автоматически вступит в силу!
Например:
@Component
@Order(Integer.MAX_VALUE - 100)
public class DemoAuthorizeConfigProvider implements AuthorizeConfigProvider {
@Override
public void config(HttpSecurity httpConfig) {
httpSecurity.authorizeRequests().antMatchers("/hello2").hasRole("admin");
}
}
Обратите внимание, что если вам нужно настроить httpSecurity.authorizeRequests() и config.anyRequest(), вы не можете сделать это в одном классе. Вам нужно создать два класса: один для настройки httpSecurity.authorizeRequests(), а другой — для настройки config.anyRequest(). И указать @Order(Integer.MAX_VALUE) для каждого класса. Например:
@Component
@Order(Integer.MAX_VALUE)
public class DemoAnyRequestAuthorizeConfigProvider implements
``` **АвторизоватьКонфигПровайдер**
@Override public void config(HttpSecurity httpSecurity) { httpSecurity.authorizeRequests().anyRequest().access("@rbacService.hasPermission(request,authentication)"); }
**Выводы:**
1. Реализовать интерфейс `АвторизоватьКонфигПровайдер`.
2. При необходимости настроить `httpSecurity.authorizeRequests().antMatchers` указать `@Order(Integer.MAX_VALUE - 100)`. Для настройки `httpSecurity.authorizeRequests().anyRequest` указать `@Order(Integer.MAX_VALUE)`.
3. Необходимо написать два разных класса для настройки `httpSecurity.authorizeRequests().anyRequest` и `httpSecurity.authorizeRequests().antMatchers`, указав разные значения `@Order`.
4. Все встроенные интерфейсы (например, проверка подлинности, вход в систему и т. д.) не требуют аутентификации для доступа. Остальные интерфейсы требуют аутентификацию (`httpSecurity.authorizeRequests().anyRequest().authenticated();`).
## **Часть вторая: common-security-browser**
### **1. Что это?**
На основе `common-security-validate` с добавлением функций выхода из системы, запоминания меня, управления сеансом и разрешения iframe. Подходит для приложений без разделения на клиентскую и серверную части (данные сеанса хранятся).
### **2. Как использовать?**
— Все параметры конфигурации должны быть добавлены в файл `security.properties`.
— После импорта jar-файла добавьте следующую аннотацию к классу запуска SpringBoot проекта:
`@ComponentScan(basePackages = {"com.chentongwei.security", "ваш пакет"})`
### **3. Конкретное использование?**
PS: Все настройки из `common-security-validate` можно использовать. В дополнение к ним были добавлены следующие три функции.
* **3.1 Выход из системы**
В файле `properties`:
`# выход из интерфейса, по умолчанию /logout`
`com.chentongwei.security.logout.logoutUrl=/logout2`
`# значение по умолчанию: /default-login.html, является ли это перенаправлением на URL или возвратом JSON, если здесь настроен URL (и не является значением по умолчанию), то это перенаправление на URL`
`com.chentongwei.security.logout.logoutSuccessUrl=/login.html`
По умолчанию интерфейс выхода — `/logout`, который можно настроить. Просто напишите его в конфигурационном файле, не нужно создавать реальный контроллер выхода. Внутренний принцип работы заключается в том, чтобы сначала удалить текущего пользователя из таблицы запоминания, а затем очистить `JSESSIONID`.
После выхода возвращается следующий JSON:
```json
{"code":200,"msg":"успешный выход"}
Пример:
<!-- Обратите внимание, что /logout2 — это конфигурация файла logoutUrl, по умолчанию — /logout -->
<a href="/logout2">Выход</a>
Предварительное условие: необходимо создать таблицу для запоминания меня. Эта таблица необходима для функции запоминания SpringSecurity. Создание таблицы:
CREATE TABLE persistent_logins (
username VARCHAR (64) NOT NULL,
series VARCHAR (64) PRIMARY KEY,
token VARCHAR (64) NOT NULL,
last_used TIMESTAMP NOT NULL
)
Настройки запоминания:
# время запоминания (по умолчанию 3600s)
# обратите внимание: необходимо заранее создать таблицу
com.chentongwei.security.rememberme.seconds=7200
Функция запоминания вкратце:
Обычно в приложениях без разделения на клиентскую и серверную стороны мы сохраняем информацию о пользователе в сеансе. Это означает, что при перезапуске сервера каждому пользователю необходимо снова войти в систему. Функция запоминания позволяет сохранить username
, token
и другую информацию в таблице, созданной ранее. Затем при первом входе в систему информация проверяется в таблице на соответствие требованиям и срок действия. Если всё в порядке, пользователь входит в систему. После успешного входа информация сохраняется в cookie
, поэтому каждый раз не требуется проверять таблицу. Таким образом, это не вызовет проблем с производительностью.
Если вы используете функцию запоминания, атрибут имени флажка должен быть remember-me
.
Пример:
<input name="remember-me" type="checkbox" value="true" />Запомнить меня
Файл properties
:
# адрес перехода после истечения срока действия сеанса, по умолчанию не настроен, без настройки возвращается JSON
com.chentongwei.security.session.sessionInvalidUrl=/login.html
# максимальное количество сеансов одного и того же пользователя, по умолчанию 1
com.chentongwei.security.session.maximumSessions=1
По умолчанию после истечения срока действия сеанс возвращает следующий JSON:
{"code":601,"msg":"срок действия сеанса истёк"}
По умолчанию, когда существует несколько сеансов одного пользователя, предыдущий сеанс будет завершён, и будет возвращён следующий JSON. Настройте sessionInvalidUrl
, чтобы перейти по указанному адресу после завершения сеанса. Если вы хотите, чтобы у одного аккаунта было несколько активных сеансов, просто измените maximumSessions
.
{"code":601,"msg":"возможно, ваш аккаунт вошёл в систему в другом месте, что привело к истечению срока действия этого сеанса"}
Файл properties
:
# разрешить фреймворк. По умолчанию 0: запретить фреймы
com.chentongwei.security.frame.disableStatus=1
По умолчанию запрещено встраивание фреймов для предотвращения атак CSRF. Если это необходимо, настройте disableStatus=1
.
Основан на common-security-validate
, с добавлением JWT, выхода из системы, управления одновременным входом пользователей и других функций. Подходит для разделения клиентской и серверной частей (данные хранятся в Redis).
— Все параметры конфигурации должны быть добавлены в файл security.properties
.
— После импорта jar-файла добавьте следующую аннотацию к классу запуска SpringBoot проекта:
@ComponentScan(basePackages = {"com.chentongwei.security", "ваш пакет"})
PS: все настройки из common-security-validate
могут быть использованы. Добавлены следующие три функции:
Пользователь войдёт в систему, и токен JWT будет возвращён в заголовке ответа. Любой защищённый интерфейс требует наличия этого токена в заголовке запроса.
Файл properties
:
# ключ подписи JWT, по умолчанию defaultSecret
com.chentongwei.security.jwt.secret=tucaole
# срок действия JWT (в секундах), по умолчанию 3600 секунд, один час
com.chentongwei.security.jwt.expiration=120
# md5Key, каждый токен имеет уникальный md5key, по умолчанию randomKey
com.chentongwei.security.jwt.md5Key=tucaolemd5
com.chentongwei.security.jwt.preventsGetMethod=false
PS: Это просто JWT, интегрированный с SpringSecurity, без интеграции с Oauth2.
3.2. Автоматическое обновление токена
# Время до истечения срока действия токена в секундах, после которого токен автоматически обновляется и помещается в заголовок. По умолчанию 60 секунд, -1 — не обновлять.
com.chentongwei.security.jwt.autoRefreshTokenExpiration=60
3.3. Параллельный вход
# Определяет, разрешено ли нескольким пользователям одновременно входить в систему под одной учётной записью. Если не разрешено, предыдущий пользователь будет «выброшен», по умолчанию false, не «выбрасывать», разрешить нескольким пользователям входить в систему, true: «выбросить».
com.chentongwei.security.jwt.preventsLogin=true
3.4. Выход из системы
# Встроенный интерфейс выхода: /jwtLogout
3.5. Переопределение обработчиков успешного/неудачного завершения аутентификации
# Нужно ли перекрывать обработчик успешного завершения аутентификации, если нужно, то указать enable=false. Имя компонента — «authenticationSuccessHandler».
com.chentongwei.security.app.success.handler.enable=false
# Нужно ли перекрывать обработчик неудачного завершения аутентификации, если нужно, то указать enable=false. Имя компонента — «authenticationFailureHandler».
com.chentongwei.security.app.failure.handler.enable=false
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )