Серия Spring Security еще не закончена, и в последнее время она все еще исследуется.
Иногда я не могу отделаться от мысли, что если мы отслеживаем Spring Security с самого его первого дня, сегодня должно быть легко вернуться к его исходному коду, потому что мы знаем причину каждой строки кода.
Однако на самом деле большинство из нас соприкасалось с ним посередине, включая самого Сун Гэ. Поэтому при чтении исходников иногда мы сталкиваемся с некоторыми вещами, которые не так просто понять, не то чтобы это сложно, но мы не разбираемся в среде разработки N лет назад, поэтому понять внешний вид непросто строки кода значение.
Итак, чтобы понять эту структуру, иногда нам нужно понять, что произошло раньше.
Это то же самое, что учить Spring Boot.Многие друзья спрашивали, стоит ли пропускать SSM.Я сказал нет, и даже написал статью(Как изучить Spring Boot? Чему научиться? Хотите сначала изучить SSM?), Пропустите SSM, многие вещи в Spring boot толком не понять.
Отодвинься. . .
Spring Security инкапсулирует запрос HttpServletRequest и переписывает несколько методов, связанных с управлением безопасностью, в HttpServletRequest.Чтобы понять переписывание в Spring Security, вы должны начать с HttpServletRequest.
Некоторые друзья могут сказать, какое отношение HttpServletRequest имеет к управлению безопасностью? Сегодня к вам придет пообщаться Brother Song.Мы не будем говорить о Spring Security, а просто поговорим о методе управления безопасностью в HttpServletRequest.
1.HttpServletRequest
В HttpServletRequest наши часто используемые методы:
- public String getHeader(String name);
- public String getParameter(String name);
- public ServletInputStream getInputStream()
- ...
Эти общие методы могут использоваться всеми, и есть несколько необычных методов, связанных с безопасностью:
public String getRemoteUser();
public boolean isUserInRole(String role);
public java.security.Principal getUserPrincipal();
public boolean authenticate(HttpServletResponse response)
throws IOException, ServletException;
public void login(String username, String password) throws ServletException;
public void logout() throws ServletException;
Три метода выше, перед Servlet там, за тремя методами, это новый способ увеличения от запуска Servlet3.0. Это видно из названия метода, и они связаны с методами аутентификации, но эти методы, я думаю, многие мелкие партнеры никогда не использовали, потому что они не очень практичны.
Во фреймворке Spring Security эти методы переписаны, что привносит некоторые интересные и удобные функции, которыми Сонге поделится с вами в следующей статье.
Чтобы понять инкапсуляцию в Spring Security, вы должны сначала посмотреть, без фреймворка, как использовать эти методы!
2. Практика приносит истинное знание
Создаем обычный веб-проект без использования какого-либо фреймворка (последние случаи на этом основаны), а затем в методе doGet выводим тип HttpServletRequest, код такой:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("request.getClass() = " + request.getClass());
}
Результат выполнения кода следующий:
request.getClass() = class org.apache.catalina.connector.RequestFacade
HttpServletRequest — это интерфейс, а RequestFacade — серьезный класс.
HttpServletRequest — это ServletRequest, определенный в спецификации сервлета, который эквивалентен стандартному запросу, однако запрос в Tomcat — это собственный пользовательский запрос Tomcat, который реализует интерфейс HttpServletRequest и определяет множество собственных методов. Он по-прежнему общедоступен. напрямую использовать пользовательский запрос Tomcat, разработчикам нужно только выполнить преобразование вниз, чтобы вызвать эти внутренние методы Tomcat.Это проблематично, поэтому мы инкапсулируем его с помощью RequestFacade, чтобы мы фактически использовали это объект RequestFacade.
Тогда нет никаких сомнений в том, что конкретная реализация метода HttpServletRequest#login выполняется в методе Request#login Tomcat. После отслеживания исходного кода мы обнаружили, что источник данных для входа предоставляется Realm в Tomcat.Обратите внимание, что это Царство не является Царством Широ.
Tomcat предоставляет 6 видов Realm, которые могут поддерживать стыковку с различными источниками данных:
- JDBCRealm: Очевидно, что это Царство может быть связано с информацией о пользователе в базе данных.
- DataSourceRealm: он ищет пользователей в реляционной базе данных через источник данных JNDI с именем JDBC.
- JNDIRealm: поиск пользователей на сервере каталогов LDAP через поставщика JNDI1.
- UserDatabaseRealm: этот источник данных находится в файле конфигурации Tomcat conf/tomcat-users.xml.
- MemoryRealm: Этот источник данных находится в памяти, и данные в памяти также загружаются из файла конфигурации Conf / Tomcat-user.xml.
- JAASRealm: архитектура JAAS для реализации аутентификации пользователя.
Если эти Царства не могут удовлетворить потребности, конечно, мы также можем настроить Царство, но обычно мы этого не делаем, почему? Потому что этот метод входа используется слишком мало! Сегодняшняя статья просто откровение для моих друзей.
Если мы настраиваем Realm, нам нужно только реализовать интерфейс org.apache.catalina.Realm, а затем поместить скомпилированный jar в $CATALINA_HOME/lib Конкретная конфигурация такая же, как описанная ниже.
Далее я представлю два метода настройки: один — UserDatabaseRealm, а другой — JDBCRealm.
2.1 Вход на основе профиля
Давайте сначала определим логинсерлет:
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
try {
req.login(username, password);
} catch (ServletException e) {
req.getRequestDispatcher("/login.jsp").forward(req, resp);
return;
}
boolean login = req.getUserPrincipal() != null && req.isUserInRole("admin");
if (login) {
resp.sendRedirect("/hello");
return;
} else {
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
}
При поступлении запроса сначала извлекаются имя пользователя и пароль, а затем вызывается метод req.login для входа в систему. Если вход не удается, выполняется переход на страницу входа.
После завершения входа в систему путем получения информации о пользователе для входа и оценки роли пользователя для входа, чтобы убедиться, что пользователь успешно вошел в систему.
Если вход выполнен успешно, он перейдет на домашнюю страницу приложения проекта, в противном случае он перейдет на страницу входа.
Затем определите HelloServlet:
@WebServlet(urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Principal userPrincipal = req.getUserPrincipal();
if (userPrincipal == null) {
resp.setStatus(401);
resp.getWriter().write("please login");
} else if (!req.isUserInRole("admin")) {
resp.setStatus(403);
resp.getWriter().write("forbidden");
}else{
resp.getWriter().write("hello");
}
}
}
В HelloServlet сначала определите, вошел ли пользователь уже в систему, если нет, верните 401, если вошел, но не имеете соответствующей роли, верните 403, в противном случае верните hello.
Затем определите LogoutServlet для выполнения операции выхода из системы:
@WebServlet(urlPatterns = "/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.logout();
resp.sendRedirect("/hello");
}
}
метод выхода из системы - HttpServletRequest.
Наконец, просто определите страницу login.jsp следующим образом:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
Все готово, и следующий шаг — источник данных.По умолчанию загружаются данные в conf/tomcat-users.xml.Находим этот файл конфигурации Tomcat.После модификации содержимое выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
<role rolename="admin"/>
<user username="javaboy" password="123" roles="admin"/>
</tomcat-users>
После завершения настройки запустите проект для тестирования. Имя пользователя для входа — javaboy, а пароль для входа — 123. Я не буду демонстрировать конкретный процесс тестирования.
2.2 Вход на основе базы данных
Если мы хотим войти в систему на основе базы данных, нам нужно сначала подготовить базу данных и таблицы.Нам нужны две таблицы, пользовательская таблица и таблица ролей, как показано ниже:
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `role` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`role_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Затем добавьте в таблицу две строки фиктивных данных:
Затем найдите файл conf/server.xml Tomcat и измените конфигурацию следующим образом:
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
driverName="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/basiclogin"
connectionName="root" connectionPassword="123"
userTable="user" userNameCol="username"
userCredCol="password"
userRoleTable="role" roleNameCol="role_name" />
</Realm>
В этой конфигурации:
- Укажите JDBCRealm.
- Указывает драйвер базы данных.
- Указывает адрес подключения к базе данных.
- Укажите имя пользователя/пароль для подключения к базе данных.
- Указывает имя пользовательской таблицы, имя поля для имени пользователя и имя поля для пароля.
- Укажите имя таблицы ролей и имя поля роли.
После завершения настройки снова войдите в тест, а данные для входа на этот раз — это данные из базы данных.
3. Оптимизация
В предыдущем HelloServlet мы вручную настроили его в коде.Если каждый сервлет настроен таким образом, это будет год обезьяны.
Таким образом, мы можем настроить это вручную в web.xml.
Сначала мы создаем AdminServlet для тестирования следующим образом:
@WebServlet(urlPatterns = "/admin/hello")
public class AdminServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello admin!");
}
}
Затем настройте в web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>admin</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>admin</role-name>
</security-role>
Эта конфигурация означает/admin/*
Путь запроса в формате должен иметь роль администратора для доступа, иначе он не будет доступен.Таким образом, каждый сервлет, связанный с администратором, защищен, и нет необходимости писать код в сервлете для оценки.
4. Резюме
Что ж, после введения в эту статью я полагаю, что у вас есть общее представление о нескольких методах аутентификации в HttpServletRequest. В следующей статье Сонг Гэ продолжит рассказывать о том, как эти методы развиваются в среде Spring Security. После прочтения этого статья, следующие статьи легко понять ~
Адрес загрузки этого дела:GitHub.com/Len VE/Java не…
Что ж, если вы чувствуете, что что-то приобрели, не забудьте нажать и подбодрить Сон Гэ~