〰️
Programming with Java
  • Програмиране с JAVA
  • Обектно-ориентирано програмиране - 1 част
    • Лабораторно упражнение 1
      • Основи на програмирането с Java за начинаещи‎
        • Oбщи термини в Java
        • Основни характеристики на JAVA‎
        • Инсталиране на JDK
        • Инсталиране на Intellij
      • Първа програма в Java
      • Системен изход в JAVA
      • Дефиниране на променливи
      • Примитивни типове данни
      • Оператори
      • If-else
      • Switch-Case
      • For loop
      • While loop
      • Do-while loop
      • Continue
      • Break
      • Задачи
    • Лабораторно упражнение 2
      • Клас
      • Обект
      • Ключова дума new
      • Запазена дума static
      • Конвенции за именуване в Java
      • Wrapper Class
      • Сравняване на
      • Нуждата Wrapper Class
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 3
      • Наследяване
      • this и super
      • Модификатори за достъп
      • Капсулиране
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 4
      • Проследяване на грешки
      • Оценяване на изрази
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 5
      • Полиморфизъм
      • Абстрактен клас
      • Интерфейс
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 6
      • Разлика между Абстрактен клас и Интерфейс
        • Разлика 1
        • Разлика 2
        • Разлика 3
        • Разлика 4
        • Разлика 5
        • Разлика 6
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 7
      • String
      • Enum
      • Обработка на изключения
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 8
      • Генерични класове
      • Генеричен метод
      • Параметри на типа в Java Generics
      • Предимства на генериците
      • Генериците работят само с референтни типове
    • Лабораторно упражнение 9
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 10
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 11
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 12
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 13
      • Упражнения за извънаудиторна заетост
      • Упражнения за извънаудиторна заетост
  • Обектно-ориентирано програмиране - 2 част
    • Лабораторно упражнение 1
      • SRP - Single Responsibility Principle
        • Задачи
      • OCP - Open-Closed Principle
        • Задачи
    • Лабораторно упражнение 2
      • LSP - Liskov Substitution Principle
        • Задачи
      • ISP - Interface Segregation Principle
        • Задачи
      • DI - Dependency Inversion Principle
        • Задачи
    • Лабораторно упражнение 3
      • Singleton
        • Задачи
      • Builder
        • Задачи
    • Лабораторно упражнение 4
      • Factory Method
      • Abstract Factory
      • Задачи
    • Лабораторно упражнение 5
    • Лабораторно упражнение 6
      • Decorator
      • Bridge
        • Композиция
      • Задачи
    • Лабораторно упражнение 7
      • Adapter
      • Задачи
    • Лабораторно упражнение 8
      • Composite
      • Proxy
      • Задачи
    • Лабораторно упражнение 9
    • Лабораторно упражнение 10
      • Visitor
      • State
      • Задачи
    • Лабораторно упражнение 11
      • Observer
      • Задачи
    • Лабораторно упражнение 12
      • Chain of Responsibility
      • Command
      • Задачи
    • Лабораторно упражнение 13
  • Интернет технологии 2023
    • Лабораторно упражнение 1
      • HTTP протокол
        • Синтаксис на URL
        • HTTP съобщения
        • Методи за HTTP заявка
        • Кодове за състояние на HTTP отговор
      • Postman
        • Изпращане на заявка с Postman
        • Получаване на отговор
      • Задачи за работа с Postman
    • Лабораторно упражнение 2
      • Работа с Tomcat
      • Maven
      • Създаване на Maven проект в IntelliJ Ultimate Edition
      • Създаване на Maven проект в IntelliJ Community Edition
      • Създаване на Maven проект в Eclipse IDE
    • Лабораторно упражнение 3
      • Java Servlets
      • Жизнен цикъл на сървлета
      • Създаване на сървлети
      • Задачи за създаване на сървлети
    • Лабораторно упражнение 4
      • Extensible Markup Language
      • Java Architecture for XML Binding
      • JavaScript Object Notation
      • Задачи
    • Лабораторно упражнение 5
    • Лабораторно упражнение 6
      • Spring Boot
      • Създаване на Spring boot проект
      • Структура на Spring Boot проект
        • Файлът pom.xml
        • Main клас в Spring Boot
        • Управление на конфигурацията с application.properties
      • Задача
    • Лабораторно упражнение 7
      • Комуникационен поток и CRUD операции
      • ResponseEntity
      • Избрани анотации
      • Задача
    • Лабораторно упражнение 8
      • Lombok
      • Data transfer object (DTO)
      • Обработване на изключения в Spring Boot приложение
        • Клас Optional<T>
      • Валидиране на данните от заявката
      • Задачи
    • Лабораторно упражнение 9-10
      • Конфигуриране на PostgreSQL DB
      • Jakarta Persistence анотации
      • Repository слой
      • Задачи
    • Лабораторно упражнение 11
      • Проследяване на сесии
      • Филтри и FilterChain
      • Spring Security
        • Добавяне на Spring Security в Spring Boot приложение
        • Конфигуриране на филтри
        • Удостоверяване със Spring Security
        • Защита на метод със Spring Security
      • Задача
    • Лабораторно упражнение 12
      • JSON Web Token
      • Защита с помощта на JWT
      • Задача
    • Лабораторно упражнение 13
  • Програмиране за мобилни и Интернет устройства
    • Лабораторно упражнение 1
      • Задачи
    • Лабораторно упражнение 2
      • Среда за разработване
        • Създаване на проект
        • Структора на проект
        • Виртуално устройство с Android OS
      • Задача
    • Лабораторно упражнение 3
      • Activity
      • Layout
        • XML описание
      • Задача
    • Лабораторно упражнение 4
      • Activity Lifecycle
      • Intent
      • Слушатели на събитията и методи за обратно извикване
      • Задача
    • Лабораторно упражнение 5
      • Слушатели на събитията и методи за обратно извикване
      • Задача
    • Лабораторно упражнение 6
      • Фрагменти
      • DialogFragment
      • Задача
    • Лабораторно упражнение 7
      • Примери
        • BaseAdapter
        • ArrayAdapter
        • Custom ArrayAdapter
      • RecyclerView
        • Пример
      • CardView
      • Задача
    • Лабораторно упражнение 8
      • Runnable
      • HandlerThread
      • ThreadPoolExecutor
      • Задача
    • Лабораторно упражнение 9
      • Задача
      • Задача
      • Пример
  • Интернет Технологии
    • Лабораторно упражнение 1
      • Инсталиране и настройка на необходимата среда за работа в упражненията
      • Maven
      • Създаване на Maven проект в Eclipse IDE
      • Създаване на Maven проект в IntelliJ
      • Работа с Tomcat
      • Задача
    • Лабораторно упражнение 2
      • HTML форми
      • Cascading Style Sheets (CSS)
        • CSS селектори
        • Някои CSS свойства
      • Задача
    • Лабораторно упражнение 3
      • Java Servlets
      • Жизнен цикъл на сървлета
      • Създаване на сървлети
      • Задачи
    • Лабораторно упражнение 4
      • Java Server Pages технология. Същност и детайли
      • Пренасочване между Servlet и JSP
      • Задачи
    • Лабораторно упражение 5
      • Build pattern
      • JavaBean
      • Задачи
    • Лабораторно упражение 6
      • Проследяване на сесии
      • Управление на бисквитки (Cookies)
      • Задачи
    • Лабораторно упражнение 7
      • Проследяване на сесии
      • Управление на бисквитки (Cookies)
      • Servlet Filter
      • Задачи
    • Лабораторно упражнение 8
      • Servlet Filter
      • Прихващане на грешки
      • Задачи
    • Лабораторно упражнение 9
      • Extensible Markup Language
      • JavaScript Object Notation
        • Fetch
      • Задача
    • Лабораторно упражнение 10
      • Java Architecture for XML Binding
      • Задачи
Powered by GitBook
On this page
  • Създаване на JWT токен
  • Оторизация с JWT токен

Was this helpful?

  1. Интернет технологии 2023
  2. Лабораторно упражнение 12

Защита с помощта на JWT

JWT е компактен начин за прилагане на удостоверяване в модерни уеб приложения. За да го приложим, ще използваме библиотеката jjwt, която е JWT библиотека за Java и Android и се използва за създаване и анализиране на JWT. Трябва да добавим следните зависимости в pom.xml.

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

Следващите стъпки демонстрират как да активирате JWT удостоверяване и упълномощаване в бекенда. За реализацията им са необходимо от предходното упражнение да сте предвидили:

· Клас със SecurityFilterChain метод за задаване на правила за упълномощаване;

· Сервизен клас с метод за вписване на потребителя;

· Клас, имплементиращ UserDetailsService и неговия метод loadUserByUsername();

· Контролер с точка за достъп за вписване на потребителя.

Създаване на JWT токен

jwt.secret=2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b
jwt.expiration-milliseconds=604800000
  1. Създайте клас с метод за генериране на токен след успешно удостоверяване на потребителя.

@Component
public class JWTTokenProvider {

    @Value("${jwt.secret}")
    private String JWTSecret;

    @Value("${jwt.expiration-milliseconds}")
    private int JWTExpirationDate;

    public String generateToken(Authentication authentication) {
        String userName = authentication.getName();
        Date currentDate = new Date();
        Date expireDate = new Date(currentDate.getTime()+JWTExpirationDate);

        String token = Jwts.builder()
                .setSubject(userName)
                .setIssuedAt(new Date())
                .setExpiration(expireDate)
                .signWith(key())
                .compact();
        return  token;
    }

    private Key key() {
        return Keys.hmacShaKeyFor(Decoders.BASE64.decode(JWTSecret));
    }
}
  1. В персонализирана реализация на SecurityFilterChain допълнете правилата с изискване сесия да не бъде създавана или използвана от Spring Security.

http.sessionManagement(session -> 
    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
  1. В метода за вписване заменете добавянето на данните на вписания потребител към сесийния обект с логика по създаване на токен. Нека методът за връща създадения токен като текст.

public String login(LoginDto loginDto) {

        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginDto.getUsername(), loginDto.getPassword()
                ));

        SecurityContext sc = SecurityContextHolder.getContext();
        sc.setAuthentication(authentication);

	//Добавяне
        String token = jwtTokenProvider.generateToken(authentication); 
	return token;

	//Премахване
       /* HttpSession session = req.getSession(true);
         session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
         return "User logged-in successfully!";*/
    }
  1. Добавете клас, с помощта на който създаденият токен да бъде върнат като отговор на клиента.

@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class JWTAuthResponse {
    private String accessToken;
    private String tokenType = "Bearer";
}
  1. По отношение на точката за достъп за вписване на потребителя задайте отговорът да включва генерирания токен.

@PostMapping("/login")
public ResponseEntity<JWTAuthResponse> login(@RequestBody LoginDto loginDto) {
    String token = authService.login(loginDto);
    JWTAuthResponse jwtAuthResponse = new JWTAuthResponse();
    jwtAuthResponse.setAccessToken(token);
    return new ResponseEntity<>(jwtAuthResponse, HttpStatus.OK);
}
  1. Изпробвайте създадената функционалност за създаване на токен c Postman.

Оторизация с JWT токен

1. Създайте клас, който имплементира интерфейса AuthenticationEntryPoint и неговия метод commence().

AuthenticationEntryPoint се използва за изпращане на HTTP отговор, който да изисква вписване от страна на клиент. Понякога клиентът проактивно включва идентификационни си данни (като потребителско име и парола), за да поиска достъп до ресурс. Тогава Spring Security не трябва да предоставя HTTP отговор, който изисква идентификационни данни от клиента, тъй като те вече са включени.

В други случаи обаче клиентът прави неупълномощена заявка към ресурс, до който не е оторизиран за достъп. В този случай се използва реализация на AuthenticationEntryPoint за изискване на идентификационни данни от клиента. Тя може да извърши пренасочване към страница за влизане, да отговори с хедър WWW-Authenticate или да предприеме друго действие. В нашия случай, тъй като нямаме налична страница за вписване, ще бъде хвърлено authException изключение.

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, 
        HttpServletResponse response, 
        AuthenticationException authException) 
        throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
    }
}

2. Допълнете класа JWTTokenProvider с методи за:

a. връщане на потребителско име от подаден токен;

b. валидиране на подаден токен;

@Component
public class JWTTokenProvider {
    
 //Предходно съдържание

        public String getUsername(String token) {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(key())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            String username = claims.getSubject();
            return username;
        }

       public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                    .setSigningKey(key())
                    .build()
                    .parse(token);
            return true;
        }
        catch (MalformedJwtException ex) {
            throw new ApiException(HttpStatus.BAD_REQUEST, "Invalid JWT token");
        }
        catch (ExpiredJwtException ex) {
            throw new ApiException(HttpStatus.BAD_REQUEST, "Expired JWT token");
        }
        catch (UnsupportedJwtException ex) {
            throw new ApiException(HttpStatus.BAD_REQUEST, "Unsupported JWT token");
        }
        catch (IllegalArgumentException ex) {
            throw new ApiException(HttpStatus.BAD_REQUEST, "JWT string claims is empty");
        }
    }
}
  1. Създайте потребителски филтър, който да използва създадения токен за удостоверяване на потребителя.

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private JWTTokenProvider jwtTokenProvider;
    private UserDetailsService userDetailsService;

    public JwtAuthenticationFilter(JWTTokenProvider jwtTokenProvider, UserDetailsService userDetailsService) {
        this.jwtTokenProvider = jwtTokenProvider;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = getTokenFromRequest(request);
        if(StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) {
            String username = jwtTokenProvider.getUsername(token);
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                    userDetails,
                    null,
                    userDetails.getAuthorities()
            );
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        }
        filterChain.doFilter(request,response);
    }

    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7, bearerToken.length());
        }
        return null;
    }
}j
  1. Включете филтъра в SecurityFilterChain метода. Нека той да се изпълнява непосредствено преди UsernamePasswordAuthenticationFilter. Добавете и JwtAuthenticationEntryPoint като ресурс, отговарящ за обработка на изключения, свързани с оторизацията.

private JwtAuthenticationEntryPoint authenticationEntryPoint;
private JwtAuthenticationFilter authenticationFilter;

***

http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling(exception -> exception.authenticationEntryPoint (authenticationEntryPoint))
  1. Изпробвайте функционалността с Postman. Полученият при вписването токен се добавя към заявката към последващ ресурс посредством опцията Bearer token.

PreviousJSON Web TokenNextЗадача

Last updated 2 years ago

Was this helpful?

1. Към application.properties добавете свойства, задаващи тайния ключ (secret) на токена и продължителността на неговата валидност в милисекунди. За криптиране на ключа можете да използвате инструмента: , а за изчисляване на продължителността на валидност на токена в милисекунди - https://www.convertworld.com/en/time/milliseconds.html.

https://emn178.github.io/online-tools/sha256.html