Рубрики
Без рубрики

Как использовать базовую аутентификацию с помощью RestTemplate в Spring Boot

В этом посте я покажу, как использовать RestTemplate для использования RESTful API, защищенного с помощью Basic Authentic… С тегами spring boot, java, rest, api.

В этом посте я покажу, как использовать RestTemplate для использования RESTful API, защищенного базовой аутентификацией. В рамках этого поста я покажу, как создать REST API, защищенный базовой аутентификацией.

Обзор

Базовая аутентификация – это один из механизмов, который вы можете использовать для защиты вашего REST API. В моем предыдущем посте я показал, как защитить REST API с помощью веб-токена Json.

Защитите REST API с помощью базовой аутентификации

Настройка REST API

Во-первых, мы покажем простой REST API для создания пользователей или извлечения пользователей из базы данных. Затем мы защитим этот REST API с помощью базового механизма аутентификации. Наконец, мы покажем, как использовать базовую аутентификацию с помощью RestTemplate для вызова этого REST API.

Наш класс RestController для этого API для создания или извлечения пользователей будет выглядеть следующим образом:

package com.betterjavacode.restdemo.controllers;

import com.betterjavacode.restdemo.dto.UserDto;
import com.betterjavacode.restdemo.managers.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class UserController
{
    @Autowired
    private UserManager userManager;

    @RequestMapping(value = "/user/", method = RequestMethod.GET)
    public ResponseEntity> listAllUsers()
    {
        List users = userManager.getAllUsers();
        if(users.isEmpty())
        {
            return new ResponseEntity>(HttpStatus.NO_CONTENT);
        }

        return new ResponseEntity<>(users, HttpStatus.OK);
    }

    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces =
            MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity getUser(@PathVariable("id") long id)
    {
        UserDto userDto = userManager.getUser(id);
        if(userDto == null)
        {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(userDto, HttpStatus.OK);
    }


    @RequestMapping(value = "/user/", method= RequestMethod.POST)
    public ResponseEntity createUser(@RequestBody UserDto userDto)
    {
        UserDto user = userManager.createUser(userDto);

        return new ResponseEntity<>(user, HttpStatus.OK);
    }

    @RequestMapping(value = "/user/{id}", method=RequestMethod.DELETE)
    public ResponseEntity deleteUser(@PathVariable("id") long id)
    {
        UserDto user = userManager.getUser(id);

        if(user == null)
        {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

        userManager.deleteUser(id);

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

Наш класс модели базы данных для пользователя будет выглядеть следующим образом:

package com.betterjavacode.restdemo.models;

import javax.persistence.*;
import java.io.Serializable;

@Entity(name = "User")
@Table(name = "users")
public class User implements Serializable
{
    private static final long serialVersionUID = 20200816121023L;

    public User()
    {

    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id", nullable=false)
    private long id;

    @Column(name="firstname", length=100)
    private String firstname;

    @Column(name="lastname", length=100)
    private String lastname;

    @Column(name="email", length=100)
    private String email;

    @Column(name="role", length=45)
    private String role;

    @Column(name="enabled")
    private boolean enabled;

    public long getId ()
    {
        return id;
    }

    public void setId (long id)
    {
        this.id = id;
    }

    public String getFirstname ()
    {
        return firstname;
    }

    public void setFirstname (String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname ()
    {
        return lastname;
    }

    public void setLastname (String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail ()
    {
        return email;
    }

    public void setEmail (String email)
    {
        this.email = email;
    }

    public String getRole ()
    {
        return role;
    }

    public void setRole (String role)
    {
        this.role = role;
    }

    public boolean isEnabled ()
    {
        return enabled;
    }

    public void setEnabled (boolean enabled)
    {
        this.enabled = enabled;
    }
}

Просто чтобы убедиться, что мы понимаем это, мы используем объект DTO UserDTO для создания и извлечения данных из базы данных. User – это объект нашей модели базы данных.

Объект UserDTO будет выглядеть следующим образом:

package com.betterjavacode.restdemo.dto;

import com.betterjavacode.restdemo.models.User;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class UserDto
{
    private String firstname;
    private String lastname;
    private String email;

    public UserDto(){}

    public UserDto(User user)
    {
        this.setEmail(user.getEmail());
        this.setFirstname(user.getFirstname());
        this.setLastname(user.getLastname());
    }

    public String getFirstname ()
    {
        return firstname;
    }

    public void setFirstname (String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname ()
    {
        return lastname;
    }

    public void setLastname (String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail ()
    {
        return email;
    }

    public void setEmail (String email)
    {
        this.email = email;
    }

}

Как только мы настроим свойства нашего приложения и создадим необходимую таблицу базы данных, мы запустим приложение.

Теперь, если мы выполним API через такой клиент, как Postman, мы сможем получить или создать пользовательский объект.

Цель состоит в том, чтобы обезопасить этот API.

Так что добавьте Spring-Security в нашей сборке проекта.

реализация “org.springframework.boot:spring-boot-starter-security”

Теперь, если мы добавим аннотацию @EnableWebSecurity в наш основной класс приложения, как показано ниже:

package com.betterjavacode.restdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@SpringBootApplication
@EnableWebSecurity
public class RestdemoApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(RestdemoApplication.class, args);
    }
}

и если мы получим доступ к API для создания пользователя, мы получим 401 несанкционированную ошибку, как показано ниже:

Базовая аутентификация

Традиционно доступ к REST API будет осуществляться на стороне сервера после того, как пользователь войдет в систему с помощью аутентификации.

Базовая аутентификация предоставляет один из способов защиты REST API. Это не самый безопасный способ по сравнению с безопасностью на основе OAuth или JWT. При базовой аутентификации клиент отправляет учетные данные в кодировке Base64 с каждым запросом, используя заголовок авторизации HTTP.

Клиент будет отправлять заголовок авторизации с каждым запросом. Всегда существует возможность компрометации этих учетных данных, даже если они закодированы в Base64. Чтобы избежать этого, мы можем использовать HTTPS.

Теперь, с точки зрения нашей реализации, мы добавим класс Security Config для настройки безопасности для нашего REST API.

package com.betterjavacode.restdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity
                .csrf().disable()
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception
    {
        auth.inMemoryAuthentication()
                .withUser("adminuser")
                .password("{noop}adminpassword")
                .roles("USER");
    }
}

метод configure в этом классе настроит базовую аутентификацию, и каждый запрос, поступающий на наш контроллер, должен быть авторизован.

метод configure Global добавит аутентификацию входящего запроса. Запросы, поступающие через контроллер, будут проверяться на наличие этих учетных данных, которые мы настроили для проверки подлинности в памяти.

ПРЕДУПРЕЖДЕНИЕ – Это не самый безопасный способ защитить ваш API. Определенно не с аутентификацией в памяти. Не используйте его в производстве.

Теперь, если мы выполним REST API через POSTMAN, мы увидим успешный ответ, как показано ниже:

RestTemplate с базовым примером аутентификации

Первоначально мы использовали POSTMAN в качестве клиента для вызова наших REST API. Но в реальном сценарии мы не будем использовать POSTMAN, вам придется вызывать эти API программно.

Мы создадим класс Rest Client и это вызовет наши API-интерфейсы при построении базовой аутентификации.

При использовании RestTemplate , который предоставляет Spring Boot, вам необходимо передавать Http-заголовки с помощью RequestEntity .

private static HttpHeaders getHeaders ()
    {
        String adminuserCredentials = "adminuser:adminpassword";
        String encodedCredentials =
                new String(Base64.encodeBase64(adminuserCredentials.getBytes()));

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "Basic " + encodedCredentials);
        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        return httpHeaders;
    }

Мы используем exchange метод из RestTemplate для вызова нашего API и Http-заголовков , которые содержат базовую аутентификацию.

Весь класс Клиент Rest будет выглядеть следующим образом:

package com.betterjavacode.restdemo;


import com.betterjavacode.restdemo.dto.UserDto;
import org.apache.tomcat.util.codec.binary.Base64;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;

public class RestClient
{
    public static final String REST_SERVICE_URL = "http://localhost:8080/user/";

    private static HttpHeaders getHeaders ()
    {
        String adminuserCredentials = "adminuser:adminpassword";
        String encodedCredentials =
                new String(Base64.encodeBase64(adminuserCredentials.getBytes()));

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "Basic " + encodedCredentials);
        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        return httpHeaders;
    }

    private static void listAllUsers()
    {
        System.out.println("Getting all users");
        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders httpHeaders = getHeaders();

        HttpEntity httpEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity responseEntity = restTemplate.exchange(REST_SERVICE_URL,
                HttpMethod.GET, httpEntity, List.class);

        if(responseEntity.hasBody())
        {
            List> users = responseEntity.getBody();

            if(users != null)
            {
                for(LinkedHashMap userMap: users)
                {
                    System.out.println("User is " + userMap.get("firstname") + " " + userMap.get(
                            "lastname"));
                }
            }
        }
        else
        {
            System.out.println("User not found");
        }

    }

    public static void main (String[] args)
    {
        listAllUsers();

        getUser(1);
    }



    private static void getUser(long id)
    {
        System.out.println("Getting a user ");

        String restUrl = REST_SERVICE_URL  + id;

        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders httpHeaders = getHeaders();

        HttpEntity httpEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity responseEntity = restTemplate.exchange(restUrl,
                HttpMethod.GET, httpEntity, String.class);

        if(responseEntity.hasBody())
        {
            JSONObject jsonObject = new JSONObject(responseEntity.getBody());

            System.out.println(jsonObject.get("firstname"));
            System.out.println(jsonObject.get("lastname"));
        }
        else
        {
            System.out.println("User not found");
        }

    }
}

Теперь, если мы выполним программу, мы увидим результат, как показано ниже:

В этом посте мы показали, как защитить REST API с помощью базовой аутентификации. Оригинальный пост был опубликован в моем блоге Лучший java-код

Оригинал: “https://dev.to/betterjavacode/how-to-use-basic-authentication-with-rest-template-in-spring-boot-20o9”