0) Предисловие
Предыдущий[широ-первый опыт]В книге объясняется простое использование Широ, который понимает, нужно ли входить в URL-адрес для доступа, и автоматически переходит на страницу входа при доступе к URL-адресу без входа в систему.
В этой статье в основном объясняется, как реализовать обработку входа в Широ.Давайте кратко поговорим о потоке обработки входа в Широ.
Обработка входа Широ вauthc
в фильтре.authc
Он решит, что если это запрос на вход, он будет обработан отдельно, поэтому запрос на вход должен быть настроен какauthc
.
Среди них запрос на вход включает два:
- доступ логин: перейти на страницу входа
- Представлять на рассмотрениеЗапись: запрос, сделанный нажатием кнопки входа на странице входа.
Когда Широ определяет, является ли это запросом на вход, он распознает, что два запроса на вход должны быть с одним и тем же адресом, иGET
Чтобы получить доступ к странице входа,POST
Войдите, чтобы отправить
// 登录请求(包括访问登录页和提交登录)
if (isLoginRequest(request, response)) {
// 提交登录
if (isLoginSubmission(request, response)) {
// 提交登录, 执行Shiro的登录逻辑
return executeLogin(request, response);
} else {
// 访问登录请求, 继续执行进入控制器
return true;
}
}
В предыдущей статье наш запрос на доступ к странице входа/login.jsp
, прямой доступ к JSP входа, если мы используемPOST
Доступ к JSP явно неразумен для использования JSP.
Поэтому мы модифицируем запрос на вход в систему, чтобы/login
, в контроллереGET
а такжеPOST
Обработка.Когда адрес запроса на вход изменен, его необходимо настроить в Shiro.
// Shiro核心配置
shiroFilter(ShiroFilterFactoryBean) {
// 登录URL(包括请求登录页和提交登录)
// 自定义的登录URL必须单独设置
loginUrl = "/login"
// ....
}
Соответственно, в контроллер добавляются два метода для обработки запроса на вход и отправки входа соответственно.
// 处理请求登录页面
@GetMapping("/login")
public String toLogin() {
return "/login";
}
// 处理提交登录
@PostMapping("/login")
public String login() {
System.out.println("处理提交登录");
return "/success";
}
Страница входа: login.jsp
<form action="/login" method="POST">
<input type="text" name="username" placeholder="用户名" value="" />
<input type="password" name="password" placeholder="密码" value="" />
<input type="submit" value="立即登录" />
</form>
После выполнения вышеуказанных операций для запуска проекта посетите/page/a
, так как не авторизованный Широ перенаправляет на/login
, введите имя пользователя и пароль на странице входа, нажмите кнопку «Войти сейчас»POST
представлено/login
, Широ обработает этот запрос на вход.
- Имя пользователя и пароль должны быть именем пользователя и паролем (Широ возьмет значения этих двух имен параметров из Запроса в качестве имени пользователя и пароля)
- Запрос должен быть POST, а адрес запроса должен быть таким же, как loginUrl в файле конфигурации Shiro.
Итак, вопрос в том, как Широ узнает, верны ли введенные имя пользователя и пароль?
Ответ должен быть не знаю, поэтому нам нужно сообщить Широ результат после проверки имени пользователя и пароля.Так как же реализовать пользовательскую проверку?
1) Пользовательский мир
Пара ШироRealm
Определение: Компонент, который может получить доступ к информации, связанной с безопасностью системы (такой как пользователи, роли, разрешения и т. д.).Realm
Реализуйте методы для записи и запроса данных, связанных с безопасностью системы, таких как пользователи, роли и разрешения.
Информация о пользователе обычно хранится в базе данных, мы можемRealm
Имя пользователя, переданное на странице входа, отправляется в базу данных для запроса пользователя и возвращает результат Широ.
Однако Широ не знает, верны ли имя пользователя и пароль, поэтому он предоставляетRealm
компоненты, давайтеRealm
Запросите информацию о пользователе и верните ее, Широ согласноRealm
Верните результат, чтобы определить, был ли вход успешным.
Например
Ты хочешь пригласить девушек на ужин, когда ты на свидании вслепую, и ты не знаешь, что девушки любят есть каждый раз, когда ты идешь на свидание вслепую.Но ты приготовил для каждой кухни соответствующий ресторан.Ты умница достаточно подготовить небольшую коробку, чтобы пустить девушек на свидание вслепую.Напишите, что вы хотите съесть, и положите в коробку, а затем вы идете в ресторан, приготовленный заранее в соответствии с содержимым коробки.Что касается ли девушка пишет карандашом или ручкой, тебе все равно, тебя волнует только то, что девушка хочет, что есть.
В приведенном выше примере вы эквивалентны Широ, подготовка различных ресторанов эквивалентна реализации различной логики входа в систему, а маленькое поле эквивалентноRealm
, Заметка, написанная девушкой, эквивалентна реализации Realm, а содержание заметки эквивалентно запрошенной информации о пользователе.Что касается того, писать ли карандашом или ручкой, то это эквивалентно методу получения информации о пользователе ( базу данных, файл или что-то другое).
Широ заботятся только о возвращаемых результатах, а не о процессе реализации Realm, запрашивающей информацию о пользователе.Realm
// 自定义查询用户信息的Realm
public class UserRealm extends AuthenticatingRealm {
// 获取用户信息的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 登录用户名
// Shiro会将提交登录传入的用户名和密码封装到UsernamePasswordToken中
String username = ((UsernamePasswordToken) token).getUsername();
// 根据用户名从数据库或其他存储中查询用户信息
// 模拟数据库查询, 返回用户信息
User dbUser = getUser(username);
// 用户不存在,当返回null时Shiro会认为用信息不存在
if (dbUser == null) {
return null;
}
// 将查询到用户信息返回给Shiro
// 参数1: Shiro会将该参数作为当前登录用户的信息保存,随时可取
// 参数2: 当前用户的密码,Shiro使用该参数和提交登录传递的密码进行判断
// 参数3: Realm名称,暂不处理
return new SimpleAuthenticationInfo(dbUser, dbUser.getPassword(), "");
}
}
- Наследовать AuthenticatingRealm и реализовать метод doGetAuthenticationInfo для получения информации о пользователе.
- Когда информация о пользователе запрашивается на основе имени пользователя, возвращается объект AuthenticationInfo, требуемый Широ (существует множество встроенных возвращаемых объектов, которые будут представлены позже).
- Если пользователь не запрошен, он вернет значение null.Если возвращенный результат равен нулю, Shiro обработает его, как если бы пользователь не существовал. На этот раз вход невозможен.
- В этом методе не оценивается, нужно ли пробовать пароль. Широ будет судить по возвращаемому результату. Если пароль правильный, вход в систему выполнен успешно. Если пароль неверный, вход невозможен.
- Широ не волнует способ получения информации о пользователе, будь то запрос к базе данных, запрос к файлу или сторонний интерфейс, если он возвращается в соответствии с форматом.
- Широ сохранит первый объект параметра возвращаемого результата.После успешного входа в систему вы можете получить соответствующую информацию о вошедшем в систему пользователе с помощью метода Широ (например, получить идентификатор пользователя для входа и т. д.)
Этот пример не подключен к базе данных, код моделирования:
// 模拟根据用户名在数据库查询用户信息
private User getUser(String username) {
// 使用"atd681"作为登录密码才能查到信息
if (!"atd681".equals(username)) {
return null;
}
User dbUser = new User();
dbUser.setUserId(1L);
dbUser.setUsername(username);
dbUser.setPassword("123");
return dbUser;
}
- Действительное имя пользователя для входа: atd681, пароль: 123, идентификатор пользователя: 1
- Ошибка входа для других пользователей
2) Настроить область
настроитьRealm
Затем вам нужно сказать Широ, какойRealm
заключается в запросе информации о пользователе, оRealm
Настроить в Широ
// 安全管理器
securityManager(DefaultWebSecurityManager) {
realm = ref("userRealm")
}
// 定义Realm
userRealm(UserRealm)
- Определить Realm в файле конфигурации Shiro
- Настройте Realm в диспетчере безопасности securityManager
начать проект, посетить/page/a
, Широ перенаправляет на страницу входа, если он не зарегистрирован. Войтиatd681/123
Вы можете успешно войти в систему и прыгать/page/a
3) Настройте страницу успеха по умолчанию
При успешном входе Широ перенаправит на страницу успеха.
- При посещении других страниц (
/page/a
) переходит к логину, если логин прошел успешно, он перейдет на целевую страницу (/page/a
) - Прямой доступ к странице входа (без целевой страницы) и переход на страницу успеха по умолчанию после успешного входа.
Страница успеха Широ по умолчанию:/
, вы можете настроить страницу успеха по умолчанию
// Shiro核心配置
shiroFilter(ShiroFilterFactoryBean) {
// 默认登录成功后跳转的页面地址
successUrl = "/index"
// 其他配置...
}
4) Обработка ошибок входа
После успешного входа обработка в контроллере не выполняетсяPOST
Как войти. Войтиatd681
Учетная запись, отличная от учетной записи, или ввод неправильного пароля приведет к сбою входа в систему, но обработка в контроллере будет выполнена.POST
Как войти. Почему???
Логика входа Широ:
- При входе на страницу входа Широ не обрабатывает, входя в контроллер
- После успешного входа перенаправить прямо на страницу успеха (без входа в контроллер)
- При сбое входа в систему введите обработку контроллера, и контроллер определяет страницу сбоя входа.
При сбое входа в систему Широ указывает причину сбоя с помощью исключения и сохраняет причину сбоя вRequest
, ключshiroLoginFailure
, в логике входа в Широ будет выдано следующее исключение:
- Пользователь не существует:
org.apache.shiro.authc.UnknownAccountException
- Неверный пароль:
org.apache.shiro.authc.IncorrectCredentialsException
При этом встроены следующие исключения, которые удобно верифицировать пользователям при их выбрасывании:
- Неправильный пользователь:
org.apache.shiro.authc.DisabledAccountException
- Заблокированный пользователь:
org.apache.shiro.authc.LockedAccountException
- Слишком много неудач:
org.apache.shiro.authc.ExcessiveAttemptsException
- Пользователь вошел в систему:
org.apache.shiro.authc.ConcurrentAccessException
В случае сбоя входа в систему соответствующее сообщение об ошибке может отображаться на странице в соответствии с исключением.В этом примере, в случае сбоя входа возвращается страница входа и отображается сообщение об ошибке.
<!-- 有登录错误信息时,根据异常显示对应的提示信息 -->
<c:if test="${shiroLoginFailure != null}">
<c:if test="${shiroLoginFailure == 'org.apache.shiro.authc.UnknownAccountException'}">用户不存在</c:if>
<c:if test="${shiroLoginFailure == 'org.apache.shiro.authc.IncorrectCredentialsException'}">密码不正确</c:if>
</c:if>
<!-- 无登录错误时 -->
<c:if test="${shiroLoginFailure == null}">你访问的页面需要先进行登录</c:if>
<form action="/login" method="post">
<input type="text" name="username" placeholder="用户名" value="" />
<input type="password" name="password" placeholder="密码" value="" />
<input type="submit" value="立即登录" />
</form>
5) Выйти
Настройте URL-адрес выхода для использованияlogout
Фильтра достаточно, Shiro по умолчанию перенаправляется на страницу входа после выхода.
// Shiro核心配置
shiroFilter(ShiroFilterFactoryBean) {
// 配置URL规则
// 有请求访问时Shiro会根据此规则找到对应的过滤器处理
filterChainDefinitionMap = [
"/page/n" : "anon", // /page/n不需要登录即可访问
"/logout" : "logout", // 登出使用logout过滤器
"/**": "authc" // 其余所有页面需要认证(authc为认证过滤器)
]
// 其他配置 ....
}
Если вы настраиваете страницу перенаправления после выхода из системы, вам необходимо вручную определить ее в файле конфигурации.logout
Фильтры (автозагрузка Широ через Spring, если он не определен)
// 手动定义Logout过滤器
// 未定义时Shiro会通过Spring自动加载
logout(LogoutFilter){
redirectUrl = "/logout_success.jsp"
}
При этом необходимо настроитьlogout_success.jsp
Вы можете получить доступ без входа в систему (anon
), если не настроено, выйдите из системы и войдитеlogout_success.jsp
Когда он не нужен, он будет перехвачен Широ (не вошел в систему в это время) и перенаправлен на вход в систему (перенаправлен на вход после успешного входа)logout_success.jsp
)
"/logout_success.jsp" : "anon", // 登出成功页不需要认证
6) Получить информацию о пользователе для входа
существует1) 自定义Realm
Это упоминается в том, что полученная информация о пользователе для входа будет сохранена Широ после успешного входа в систему Широ предоставляет метод для получения информации о пользователе для входа в систему.
@RequestMapping("/page/a")
public String toPageA(ModelMap map) {
// Shiro提供的获取当前登录用户信息的静态方法
// 用户信息对象为在Realm中保存的对象
User user = (User) SecurityUtils.getSubject().getPrincipal();
// 获取用户ID,用户名
map.put("userId", user.getUserId());
map.put("userName", user.getUsername());
return "/page_a";
}
Полученный пользовательский объект должен соответствоватьRealm
вернуться вSimpleAuthenticationInfo
Первый параметр в объекте тот же
7) Пример кода
На данный момент пример конфигурации на основе аутентификации Широ завершен.
- Пример кода адреса:GitHub.com/at 681/все…
- Пример имени проекта: atd681-shiro-authc