Java >> Java tutorial >  >> Java

Sådan bruger du grundlæggende godkendelse til hvileskabelon

I dette indlæg vil jeg vise, hvordan du bruger Rest Template til at forbruge RESTful API sikret med Basic Authentication. Som en del af dette indlæg vil jeg vise, hvordan man bygger en REST API, der er sikret med Basic Authentication.

Oversigt

Grundlæggende godkendelse er en af ​​de mekanismer, du kan bruge til at sikre din REST API. I mit tidligere indlæg viste jeg, hvordan man sikrer REST API med Json Web Token.

Sikre en REST API med grundlæggende godkendelse

Konfigurer en REST API

For det første vil vi vise en simpel REST API til at oprette brugere eller hente brugere fra databasen. Derefter vil vi sikre denne REST API med en grundlæggende godkendelsesmekanisme. Til sidst vil vi vise, hvordan du bruger Basic Authentication with Rest Template til at kalde denne REST API.

Vores REST-controllerklasse for denne API til at oprette eller hente brugere vil se ud som nedenfor:


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

Vores databasemodelklasse for bruger vil se ud som nedenfor:


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

Bare for at sikre, at vi forstår det her, bruger vi et DTO-objekt UserDto at oprette og hente data fra databasen. User er vores databasemodelobjekt.

UserDto objekt vil være som følger:


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

}

Når vi har konfigureret vores applikationsegenskaber og oprettet den nødvendige databasetabel, starter vi applikationen.

Hvis vi nu udfører API'et gennem en klient som Postman, vil vi være i stand til at hente eller oprette brugerobjektet.

Målet er at sikre denne API.

Så tilføj Spring-Security i vores projektopbygning.

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

Nu, hvis vi tilføjer annotationen @EnableWebSecurity i vores hovedapplikationsklasse som nedenfor:


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

og hvis vi får adgang til API'et for at oprette bruger, får vi 401 unauthorized fejl som nedenfor:

Grundlæggende godkendelse

Traditionelt vil adgang til REST API ske på serversiden, når brugeren er logget på med godkendelse.

Grundlæggende godkendelse giver en af ​​måderne til at sikre REST API. Det er ikke den mest sikre måde sammenlignet med OAuth- eller JWT-baseret sikkerhed. I Basic Authentication sender en klient Base64-kodede legitimationsoplysninger med hver anmodning ved hjælp af HTTP Authorization Header .

Klienten sender autorisationshovedet med hver anmodning. Der er altid en mulighed for at kompromittere disse legitimationsoplysninger, selv når de er Base64-kodet. For at undgå det kan vi bruge HTTPS.

Nu fra vores implementeringsperspektiv vil vi tilføje en SecurityConfig klasse for at konfigurere sikkerhed for vores 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 metode i denne klasse vil konfigurere grundlæggende godkendelse, og hver anmodning, der kommer til vores controller, skal godkendes.

configureGlobal metode vil tilføje godkendelse af den indkommende anmodning. De anmodninger, der kommer gennem controlleren, vil blive valideret for disse legitimationsoplysninger, som vi har konfigureret til godkendelse i hukommelsen.

ADVARSEL – Dette er ikke den mest sikre måde at sikre din API på. Absolut ikke med in-memory-godkendelse. Brug det ikke i produktionen.

Hvis vi nu udfører REST API gennem POSTMAN, vil vi se det vellykkede svar som nedenfor:

Hvile skabelon med grundlæggende godkendelseseksempel

I starten brugte vi POSTMAN som klient til at kalde vores REST API'er. Men i et rigtigt scenarie bruger vi ikke POSTMAN, du bliver nødt til at kalde disse API'er programmatisk.

Vi vil oprette en klasse RestClient og det vil kalde vores API'er, mens vi bygger grundlæggende godkendelse.

Mens du bruger RestTemplate som Spring Boot giver, skal du bestå HttpHeaders med en 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;
    }

Vi bruger exchange metode fra RestTemplate at kalde vores API og HttpHeaders der indeholder grundlæggende godkendelse.

Hele klassen  RestClient vil se ud som nedenfor:


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

    }
}

Hvis vi nu udfører programmet, vil vi se output som nedenfor:

I dette indlæg viste vi, hvordan man sikrer REST API med Basic Authentication. Hvis du kunne lide dette indlæg, så abonner på min blog her.

Vil du vide det grundlæggende i Spring Security? Jeg lancerer min nye bog "Simplifing Spring Security " snart. Kom på min lanceringsliste for at få opdateringer og rabatkoder.

Referencer

  1. Forårs hvileskabelon –  dokumentation
  2. Spring Boot Rest-skabelon – Anvendelse

Java tag