Тебе больно модернизировать старые логины на основе форм? Так не должно быть. Отсутствие поддержки в базовой структуре может усложнить добавление поддержки OAuth 2.0 в унаследованные приложения, но в этом сообщении в блоге будет показан простой способ использования Spring Cloud Gateway и Okta для защиты ваших унаследованных приложений.
Узнайте, как настроить Spring Cloud Gateway как отдельное приложение, которое передает HTTP-запросы и обрабатывает OAuth перед отправкой запроса в ваше приложение.
Создать проект Spring Cloud Gateway
Первым шагом является создание нового проекта на Spring Initializr . Я обычно создаю его из своей IDE или командной строки:
Оболочка
1
curl https://start.spring.io/starter.tgz -d dependencies=okta,cloud-gateway,cloud-security \
2
-d groupId=com.okta.tutorial \
3
-d artifactId=example-gateway \
4
-d packageName=com.okta.tutorial \
5
-d baseDir=cloud-gateway \
6
-d bootVersion=2.2.2.RELEASE | tar -xzvf -
7
cd cloud-gateway
Если вы создаете проект через IDE или веб-интерфейс, используйте зависимости «Okta», «Gateway» и «Cloud Security». |
Переименуйте ваше src/main/resources/application.properties
в application.yml
(подробнее об этом чуть позже).
Затем защитите новое приложение с помощью OIDC / OAuth 2.0.
Если у вас уже есть учетная запись Okta, см. Ниже боковую панель « Создание веб-приложения в Okta» . В противном случае мы создали плагин Maven, который настраивает бесплатную учетную запись разработчика Okta + приложение OIDC (менее чем за минуту!).
Чтобы использовать его, запустите: ./mvnw com.okta:okta-maven-plugin:setup
создайте учетную запись и настройте приложение Spring Boot для работы с Okta.
Создать веб-приложение в Okta
Войдите в свою учетную запись Okta Developer (или зарегистрируйтесь, если у вас нет учетной записи).
-
На странице « Приложения» выберите « Добавить приложение» .
-
На странице создания нового приложения выберите Интернет .
-
Присвойте своему приложению запоминающееся имя, добавьте
http://localhost:8080/login/oauth2/code/okta
URI перенаправления входа в систему, выберите « Обновить токен» (в дополнение к коду авторизации ) и нажмите « Готово» .
Скопируйте издателя (находится в разделе « API > Серверы авторизации» ), идентификатор клиента и секрет клиента application.yml
для обоих проектов.
YAML
xxxxxxxxxx
1
okta
2
oauth2
3
issuer $ yourOktaDomain /oauth2/default
4
client-id $ clientId
5
client-secret $ clientSecret
6
Настройка маршрутов Spring Cloud Gateway
Далее вы настроите Spring Cloud Gateway для пересылки маршрутов в ваше устаревшее приложение. Для этого поста унаследованное приложение обслуживает два пути /
и /profile
.
Еще раз в свой application.yml
файл, добавьте следующий блок:
xxxxxxxxxx
1
spring
2
cloud
3
gateway
4
routes
5
id servlet-app
6
uri http //localhost8000
7
predicates
8
Path=/profile,/
9
filters
10
TokenRelay=
Базовый URL для "устаревшего" приложения. | |
Определите два пути для пересылки: /profile и/ |
|
Включение токенов доступа OAuth в запрос ниже |
Если это слишком много для YAML, замените указанный выше блок следующим Java-кодом в DemoApplication
:
Джава
xxxxxxxxxx
1
package com.okta.tutorial;
2
import org.springframework.boot.SpringApplication;
4
import org.springframework.boot.autoconfigure.SpringBootApplication;
5
import org.springframework.cloud.gateway.route.RouteLocator;
6
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
7
import org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory;
8
import org.springframework.context.annotation.Bean;
9
11
public class DemoApplication {
12
public static void main(String[] args) {
14
SpringApplication.run(DemoApplication.class, args);
15
}
16
18
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, TokenRelayGatewayFilterFactory tokenRelay) {
19
return builder.routes()
20
.route("servlet-app", r -> r.path("/profile", "/")
21
.filters(f -> f.filter(tokenRelay.apply()))
22
.uri("http://localhost:8000"))
23
.build();
24
}
25
}
Это оно! Запустите его, запустив ./mvnw spring-boot:run
.
Краткий обзор, прежде чем мы продолжим: у этого application.yml
много чего происходит. Он содержит конфигурацию OAuth 2.0 (издатель, идентификатор клиента, секрет клиента) и все необходимое для безопасного прокси-сервера для унаследованного приложения.
Обновите устаревшее приложение
Обновление унаследованного приложения обычно не просто; если бы это было так, вы бы, вероятно, не присвоили бы ему ярлык "legacy"! Чтобы сосредоточиться, я создал простое приложение с сервлетами, которое содержит один сервлет:
Джава
xxxxxxxxxx
1
name = "UserProfile", urlPatterns = {"/", "/profile"}) (
2
public class UserProfileServlet extends HttpServlet {
3
5
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
6
request.setAttribute("email", "jill.coder@example.com"); // faking an existing service
8
Map<String, String> attributes = new HashMap<String, String>();
9
attributes.put("sub", "jill.coder@example.com"); // more fake data
10
request.setAttribute("userAttributes", attributes);
11
request.getRequestDispatcher("/WEB-INF/user-profile.jsp").forward(request, response);
13
}
14
}
Получите полный код на GitHub (в original-servlet-app
ветке):
Оболочка
xxxxxxxxxx
1
git clone https://github.com/oktadeveloper/okta-legacy-with-cloud-gateway-example.git -b original-servlet-app
2
cd okta-legacy-with-cloud-gateway-example/legacy-servlet-app
В приведенном выше примере используются статические строки, реальное приложение, вероятно, имеет форму для сбора имени пользователя и пароля вместе с пользовательской службой, которая подключается к базе данных; Вы можете использовать свое воображение.
Запустите это приложение ./mvnw jetty:run
и перейдите к http://localhost:8080
.
Это приложение работает на порту, 8000 а приложение шлюза выше на порту 8080 . Убедитесь, что вы используете 8080 URL для доступа к приложению через шлюз. |
Превратите устаревшее приложение в сервер ресурсов OAuth
Теперь вы можете получить доступ к сервлет-приложению через Spring Cloud Gateway! Теперь пришло время обеспечить это. Для этого добавьте сервлет Filter
для проверки токена доступа, добавленного Spring Cloud Gateway.
Добавить новый класс: src/main/java/com/okta/example/BearerTokenFilter.java
Джава
xxxxxxxxxx
1
package com.okta.example;
2
import com.okta.jwt.AccessTokenVerifier;
4
import com.okta.jwt.Jwt;
5
import com.okta.jwt.JwtVerificationException;
6
import com.okta.jwt.JwtVerifiers;
7
import javax.servlet.Filter;
9
import javax.servlet.FilterChain;
10
import javax.servlet.FilterConfig;
11
import javax.servlet.ServletException;
12
import javax.servlet.ServletRequest;
13
import javax.servlet.ServletResponse;
14
import javax.servlet.annotation.WebFilter;
15
import javax.servlet.http.HttpServletRequest;
16
import javax.servlet.http.HttpServletResponse;
17
import java.io.IOException;
18
urlPatterns = "*") (
20
public class BearerTokenFilter implements Filter {
21
public static final String ACCESS_TOKEN = "jwtAccessToken";
23
private static final String ISSUER_KEY = "okta.oauth2.issuer";
24
private AccessTokenVerifier tokenVerifier;
26
public void init(FilterConfig filterConfig) throws ServletException {
28
String issuer = System.getProperty(ISSUER_KEY, filterConfig.getInitParameter(ISSUER_KEY));
29
tokenVerifier = JwtVerifiers.accessTokenVerifierBuilder()
30
.setIssuer(issuer)
31
.build();
32
}
33
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
35
HttpServletRequest request = (HttpServletRequest) servletRequest;
37
HttpServletResponse response = (HttpServletResponse) servletResponse;
38
String authHeader = request.getHeader("Authorization");
39
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
41
request.getServletContext().log("Missing or invalid 'Authorization' header");
42
respondWith401(response);
43
return;
44
}
45
String token = authHeader.replaceFirst("^Bearer ", "");
47
try {
49
Jwt jwtAccessToken = tokenVerifier.decode(token);
50
// invalid access tokens will throw an exception
51
// add the access token as a request attribute
52
request.setAttribute(ACCESS_TOKEN, jwtAccessToken);
53
filterChain.doFilter(request, response);
54
} catch (JwtVerificationException e) {
55
request.getServletContext().log("Failed to parse access token", e);
56
respondWith401(response);
57
}
58
}
59
private void respondWith401(HttpServletResponse response) throws IOException {
61
response.setStatus(401);
62
response.setHeader("WWW-Authenticate","Bearer");
63
response.getWriter().write("Authentication required");
64
}
65
public void destroy() {
67
tokenVerifier = null;
68
}
69
}
Обновите сервлет с данными токена доступа
Последний шаг - обновить UserProfileServlet
данные токена доступа JWT. Для этого замените doGet()
метод следующим:
Джава
xxxxxxxxxx
1
2
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
3
Jwt accessToken = (Jwt) request.getAttribute(BearerTokenFilter.ACCESS_TOKEN);
5
request.setAttribute("email", accessToken.getClaims().get("sub"));
6
request.setAttribute("userAttributes", accessToken.getClaims());
7
request.getRequestDispatcher("/WEB-INF/user-profile.jsp").forward(request, response);
9
}
Протестируйте ваше безопасное приложение!
Перед перезапуском приложения сервлета захватите URL-адрес «эмитента», который вы использовали на первом шаге, скопировав его src/main/resources/application.yml
. Это также можно найти в консоли администратора Okta в разделе « API» → « Серверы авторизации» .
Запустите старое приложение с:
Оболочка
xxxxxxxxxx
1
./mvnw jetty:run -Dokta.oauth2.issuer=${yourIssuer}
Вот и все! Откройте инкогнито / приватный браузер и перейдите туда, http://localhost:8080/
где вы будете перенаправлены в Okta для входа, а затем вернитесь на страницу профиля!
Узнайте больше о веб-безопасности Java
В этом посте вы узнали, как защитить простое приложение с сервлетами с помощью OAuth 2.0 и всего лишь нескольких строк кода (плюс здоровая доза настройки и обработки ошибок). Вы также использовали Spring Cloud Gateway для прокси и защиты запросов еще до того, как они попадут в ваше приложение!
Полный исходный код этого поста доступен на GitHub .
Если вы хотите узнать больше о Java, Spring и защите приложений, ознакомьтесь со следующими статьями:
- Безопасность метода Spring с помощью PreAuthorize
- Angular 8 + Spring Boot 2.2: создайте приложение CRUD сегодня!
- Краткое руководство по параметрам входа в Spring Boot
To discover more posts like this one, follow @oktadev on Twitter and subscribe to our YouTube channel.