Sichere Spring Boot RESTful Service mit Basic Authentication
View more Tutorials:


Der Unterlagen wird nach ... geschrieben
-
Spring Boot 2.x (Or >= 1.5.9)
-
Eclipse 4.7 Oxygen
Mehr sehen
Im Artikel leite ich Sie bei der Erstellung einer Appkikation RESTful Web Service an und sichere sie mit Basic Authentication. D.h bietet Ihre Applikation die Ressources aber wenn der Benutzer die Ressources benutzen möchte, soll er mit der Basic Authentication bestätigt werden (authenticate)
Basic Authentication (die Basisbestätigung)
Um den durch Basic Authentication gesicherten Ressourcen zuzugreifen, soll der Benutzer ein request schicken und im request gibt es die Information von username/password , die auf Header angefügt wird.
Sie können den Browser zum Zugang einer durch Basic Authentication gesicherten Ressourcen verwenden. In diesem Fall wird ein Dialog angezeigt damit Sie sername/password eingeben können. Diese Information wird im request zum Schicken nach REST Server angefügt.

Auf Eclipse erstellen Sie ein Projekt Spring Boot.
Geben Sie ein
- Name: SbRestBasicAuthentication
- Group: org.o7planning
- Package: org.o7planning.sbrestbasicauth

Zunächst sollen sie die Technologie zum Verwendung wählen

SbRestBasicAuthenticationApplication.java
package org.o7planning.sbrestbasicauth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SbRestBasicAuthenticationApplication {
public static void main(String[] args) {
SpringApplication.run(SbRestBasicAuthenticationApplication.class, args);
}
}
In diesem Beispiel brauchen Sie eine Bibliothek um vom XML zu Java umzuwandeln (convert) und umgekehrt und eine Bibliothek umvom JSON zu Java umzuwandeln und umgekehrt
JSON <==> Java
spring-boot-starter-web hat die Bibliothek jackson-databind schon integriert. Diese Bibliothek hilft bei der Umwandlung von JSON zu Java und umgekehrt

XML <==> Java
Spring Boot verwendet JAXB (in JDK verfügbar) als eine Standard-Bibliothek um vom XML und Java umzuwandeln. Allerdings brauchen die Klasse von Ihrem Java durch @XmlRootElement,... annotiert zu werden. Deshalb sollen Sie meiner Meinung nach jackson-dataformat-xml wie eine Bibliothek der Umwandlung vom XML und Java verwenden. Um jackson-dataformat-xml zu benutzen sollen Sie es in die File pom.xml deklarieren:
** pom.xml **
...
<dependencies>
...
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
...
</dependencies>
...


pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.o7planning</groupId>
<artifactId>SbRestBasicAuthentication</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SbRestBasicAuthentication</name>
<description>Spring Boot +Rest + Basic Authentication</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Die Sicherheitskonfiguration werden in der Klasse WebSecurityConfig geschrieben. Im Artikel fokusiere ich auf "Wie holen Sie den Username in der Database" nicht. Deshalb erstellen Sie 2 stabilen UserName und speichern in dem Speicher. Der Benutzer grifft in die Ressourcen vom REST Service durch die Anmeldung mit einer der 2 username zu.
WebSecurityConfig.java
package org.o7planning.sbrestbasicauth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
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;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationEntryPoint authEntryPoint;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// All requests send to the Web Server request must be authenticated
http.authorizeRequests().anyRequest().authenticated();
// Use AuthenticationEntryPoint to authenticate user/password
http.httpBasic().authenticationEntryPoint(authEntryPoint);
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
String password = "123";
String encrytedPassword = this.passwordEncoder().encode(password);
System.out.println("Encoded password of 123=" + encrytedPassword);
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> //
mngConfig = auth.inMemoryAuthentication();
// Defines 2 users, stored in memory.
// ** Spring BOOT >= 2.x (Spring Security 5.x)
// Spring auto add ROLE_
UserDetails u1 = User.withUsername("tom").password(encrytedPassword).roles("USER").build();
UserDetails u2 = User.withUsername("jerry").password(encrytedPassword).roles("USER").build();
mngConfig.withUser(u1);
mngConfig.withUser(u2);
// If Spring BOOT < 2.x (Spring Security 4.x)):
// Spring auto add ROLE_
// mngConfig.withUser("tom").password("123").roles("USER");
// mngConfig.withUser("jerry").password("123").roles("USER");
}
}
Die Klasse AuthenticationEntryPointImpl weitert aus der Klasse BasicAuthenticationEntryPoint aus, Sie wird verwendet um zu prüfen, ob username/password anbei request gültig oder nicht ist
AuthenticationEntryPointImpl.java
package org.o7planning.sbrestbasicauth.auth;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class AuthenticationEntryPointImpl extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 - " + authEx.getMessage());
}
@Override
public void afterPropertiesSet() throws Exception {
// RealmName appears in the login window (Firefox).
setRealmName("o7planning");
super.afterPropertiesSet();
}
}

Die Klasse Employee vertritt einen Mitarbeiter
Employee.java
package org.o7planning.sbrestbasicauth.model;
public class Employee {
private String empNo;
private String empName;
private String position;
public Employee() {
}
public Employee(String empNo, String empName, String position) {
this.empNo = empNo;
this.empName = empName;
this.position = position;
}
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
}
Die Klasse EmployeeDAO wird durch @Repository annotiert um mit Spring zu informieren, dass es Spring BEAN ist. Diese Klasse schließt die Methode zum Abfragen der Liste der Mitarbeiter (employee), der Erstellung des Mitarbeiter, der Änderung und der Löschung der Information ein.
EmployeeDAO.java
package org.o7planning.sbrestbasicauth.dao;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.o7planning.sbrestbasicauth.model.Employee;
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeDAO {
private static final Map<String, Employee> empMap = new HashMap<String, Employee>();
static {
initEmps();
}
private static void initEmps() {
Employee emp1 = new Employee("E01", "Smith", "Clerk");
Employee emp2 = new Employee("E02", "Allen", "Salesman");
Employee emp3 = new Employee("E03", "Jones", "Manager");
empMap.put(emp1.getEmpNo(), emp1);
empMap.put(emp2.getEmpNo(), emp2);
empMap.put(emp3.getEmpNo(), emp3);
}
public Employee getEmployee(String empNo) {
return empMap.get(empNo);
}
public Employee addEmployee(Employee emp) {
empMap.put(emp.getEmpNo(), emp);
return emp;
}
public Employee updateEmployee(Employee emp) {
empMap.put(emp.getEmpNo(), emp);
return emp;
}
public void deleteEmployee(String empNo) {
empMap.remove(empNo);
}
public List<Employee> getAllEmployees() {
Collection<Employee> c = empMap.values();
List<Employee> list = new ArrayList<Employee>();
list.addAll(c);
return list;
}
}
Die Klasse MainRESTController wird durch @RestController annotiert um mit Spring zu informieren, dass es Spring Restful Controller ist,
MainRESTController.java
package org.o7planning.sbcrudrestful.controller;
import java.util.List;
import org.o7planning.sbcrudrestful.dao.EmployeeDAO;
import org.o7planning.sbcrudrestful.model.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MainRESTController {
@Autowired
private EmployeeDAO employeeDAO;
@RequestMapping("/")
@ResponseBody
public String welcome() {
return "Welcome to RestTemplate Example.";
}
// URL:
// http://localhost:8080/SomeContextPath/employees
// http://localhost:8080/SomeContextPath/employees.xml
// http://localhost:8080/SomeContextPath/employees.json
@RequestMapping(value = "/employees", //
method = RequestMethod.GET, //
produces = { MediaType.APPLICATION_JSON_VALUE, //
MediaType.APPLICATION_XML_VALUE })
@ResponseBody
public List<Employee> getEmployees() {
List<Employee> list = employeeDAO.getAllEmployees();
return list;
}
// URL:
// http://localhost:8080/SomeContextPath/employee/{empNo}
// http://localhost:8080/SomeContextPath/employee/{empNo}.xml
// http://localhost:8080/SomeContextPath/employee/{empNo}.json
@RequestMapping(value = "/employee/{empNo}", //
method = RequestMethod.GET, //
produces = { MediaType.APPLICATION_JSON_VALUE, //
MediaType.APPLICATION_XML_VALUE })
@ResponseBody
public Employee getEmployee(@PathVariable("empNo") String empNo) {
return employeeDAO.getEmployee(empNo);
}
// URL:
// http://localhost:8080/SomeContextPath/employee
// http://localhost:8080/SomeContextPath/employee.xml
// http://localhost:8080/SomeContextPath/employee.json
@RequestMapping(value = "/employee", //
method = RequestMethod.POST, //
produces = { MediaType.APPLICATION_JSON_VALUE, //
MediaType.APPLICATION_XML_VALUE })
@ResponseBody
public Employee addEmployee(@RequestBody Employee emp) {
System.out.println("(Service Side) Creating employee: " + emp.getEmpNo());
return employeeDAO.addEmployee(emp);
}
// URL:
// http://localhost:8080/SomeContextPath/employee
// http://localhost:8080/SomeContextPath/employee.xml
// http://localhost:8080/SomeContextPath/employee.json
@RequestMapping(value = "/employee", //
method = RequestMethod.PUT, //
produces = { MediaType.APPLICATION_JSON_VALUE, //
MediaType.APPLICATION_XML_VALUE })
@ResponseBody
public Employee updateEmployee(@RequestBody Employee emp) {
System.out.println("(Service Side) Editing employee: " + emp.getEmpNo());
return employeeDAO.updateEmployee(emp);
}
// URL:
// http://localhost:8080/SomeContextPath/employee/{empNo}
@RequestMapping(value = "/employee/{empNo}", //
method = RequestMethod.DELETE, //
produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
@ResponseBody
public void deleteEmployee(@PathVariable("empNo") String empNo) {
System.out.println("(Service Side) Deleting employee: " + empNo);
employeeDAO.deleteEmployee(empNo);
}
}
Erklären:
- produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }
- produces = { "application/json" , "application/xml" }
Das Attribut produces wird verwendet um zu regeln, ein URL erstellt (dem Benutzer zurückgeben) nur die Daten mit einer Format. Z.B "application/json", "application/xml".
Um die Applikation durchzuführen, klicken Sie die Rechtmaustaste aufs Project und wählen:
- Run As/Spring Boot App


Die Applikation mit dem Browser prüfen

Mehr sehen