Java >> Java Tutorial >  >> Java

So verwenden Sie die Standardauthentifizierung für Rest-Vorlagen

In diesem Beitrag werde ich zeigen, wie man Rest Template verwendet, um die RESTful-API zu nutzen, die mit Basic Authentication gesichert ist. Als Teil dieses Beitrags werde ich zeigen, wie man eine REST-API erstellt, die mit Basic Authentication gesichert ist.

Übersicht

Die Standardauthentifizierung ist einer der Mechanismen, die Sie verwenden können, um Ihre REST-API zu sichern. In meinem vorherigen Beitrag habe ich gezeigt, wie man die REST-API mit Json Web Token sichert.

Sichern Sie eine REST-API mit Standardauthentifizierung

Konfigurieren Sie eine REST-API

Zunächst zeigen wir eine einfache REST-API zum Erstellen von Benutzern oder zum Abrufen von Benutzern aus der Datenbank. Anschließend sichern wir diese REST-API mit einem einfachen Authentifizierungsmechanismus. Zuletzt zeigen wir, wie Sie die Standardauthentifizierung mit Rest-Vorlage verwenden, um diese REST-API aufzurufen.

Unsere REST-Controller-Klasse für diese API zum Erstellen oder Abrufen von Benutzern sieht wie folgt aus:


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<List> listAllUsers()
    {
        List users = userManager.getAllUsers();
        if(users.isEmpty())
        {
            return new ResponseEntity<List>(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);
    }
}

Unsere Datenbankmodellklasse für Benutzer sieht wie folgt aus:


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;
    }
}

Nur um sicherzustellen, dass wir das hier verstehen, verwenden wir ein DTO-Objekt UserDto um die Daten aus der Datenbank zu erstellen und abzurufen. User ist unser Datenbankmodellobjekt.

Die UserDto Objekt sieht wie folgt aus:


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;
    }

}

Sobald wir unsere Anwendungseigenschaften konfiguriert und die erforderliche Datenbanktabelle erstellt haben, starten wir die Anwendung.

Wenn wir nun die API über einen Client wie Postman ausführen, können wir das Benutzerobjekt abrufen oder erstellen.

Das Ziel ist es, diese API zu sichern.

Fügen Sie also Spring-Security hinzu in unserem Projektaufbau.

implementation "org.springframework.boot:spring-boot-starter-security"

Wenn wir nun die Anmerkung @EnableWebSecurity hinzufügen in unserer Hauptanwendungsklasse wie unten:


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);
	}
}

und wenn wir auf die API zugreifen, um Benutzer zu erstellen, erhalten wir 401 unauthorized Fehler wie unten:

Grundlegende Authentifizierung

Herkömmlicherweise erfolgt der Zugriff auf die REST-API auf der Serverseite, sobald sich der Benutzer mit Authentifizierung angemeldet hat.

Die Standardauthentifizierung bietet eine der Möglichkeiten zum Sichern der REST-API. Im Vergleich zu OAuth- oder JWT-basierter Sicherheit ist dies nicht der sicherste Weg. Bei der Standardauthentifizierung sendet ein Client Base64-codierte Anmeldeinformationen bei jeder Anfrage mit HTTP Authorization Header .

Der Client sendet den Authorization-Header mit jeder Anfrage. Es besteht immer die Möglichkeit, diese Anmeldeinformationen zu kompromittieren, selbst wenn sie Base64-codiert sind. Um dies zu vermeiden, können wir HTTPS verwenden.

Aus unserer Implementierungsperspektive fügen wir nun einen SecurityConfig hinzu Klasse zum Konfigurieren der Sicherheit für unsere 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 -Methode in dieser Klasse konfiguriert die grundlegende Authentifizierung und jede an unseren Controller eingehende Anfrage muss autorisiert werden.

configureGlobal -Methode fügt die Authentifizierung der eingehenden Anfrage hinzu. Die über den Controller eingehenden Anfragen werden für diese Anmeldeinformationen validiert, die wir für die In-Memory-Authentifizierung konfiguriert haben.

WARNUNG – Dies ist nicht die sicherste Art, Ihre API zu sichern. Definitiv nicht mit In-Memory-Authentifizierung. Verwenden Sie es nicht in der Produktion.

Wenn wir nun die REST-API über POSTMAN ausführen, sehen wir die erfolgreiche Antwort wie folgt:

Rest-Vorlage mit Basis-Authentifizierungsbeispiel

Ursprünglich haben wir POSTMAN als Client verwendet, um unsere REST-APIs aufzurufen. Aber in einem realen Szenario werden wir POSTMAN nicht verwenden, Sie müssen diese APIs programmgesteuert aufrufen.

Wir erstellen eine Klasse RestClient und das wird unsere APIs aufrufen, während die Basisauthentifizierung erstellt wird.

Bei Verwendung von RestTemplate die Spring Boot bereitstellt, müssen Sie HttpHeaders übergeben mit einem 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;
    }

Wir verwenden exchange Methode aus RestTemplate um unsere API aufzurufen und HttpHeaders die die Standardauthentifizierung enthalten.

Die ganze Klasse  RestClient wird wie folgt aussehen:


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<LinkedHashMap<String, Object>> users = responseEntity.getBody();

            if(users != null)
            {
                for(LinkedHashMap<String, Object> 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");
        }

    }
}

Wenn wir nun das Programm ausführen, sehen wir die Ausgabe wie unten:

In diesem Beitrag haben wir gezeigt, wie man die REST-API mit Basic Authentication sichert. Wenn Ihnen dieser Beitrag gefallen hat, abonnieren Sie hier meinen Blog.

Möchten Sie die Grundlagen von Spring Security kennenlernen? Ich veröffentliche mein neues Buch „Simplifying Spring Security " demnächst. Tragen Sie sich in meine Startliste ein, um Updates und Rabattcodes zu erhalten.

Referenzen

  1. Frühlingsruhe-Vorlage –  Dokumentation
  2. Spring Boot Rest Template – Verwendung

Java-Tag