Crea un api REST de la forma más simple con Java y Spring Data REST


En posts anteriores se explicó como hacer una API rest utilizando Spring Data, Spring REST y Spring Boot, en este post se explicará una forma aún más simple de hacerlo haciendo uso de Spring Data REST.

1. Configuración

El primer paso será crear un proyecto Maven que tenga como padre el siguiente proyecto:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
</parent>

Una vez que se definió el padre se deben definir las siguientes dependencias:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-rest</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	</dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<scope>provided</scope>
	</dependency>
</dependencies>

El último paso es definir un plugin de Maven:

<build>
	<plugins>
		<plugin>
			<artifactId>maven-compiler-plugin</artifactId>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
			</configuration>
		</plugin>
	</plugins>
</build>

2. Creación de tabla y creación de datos de prueba

Para exponer información en nuestra api es necesario crear una tabla donde almacenar nuestros registros y algunos registros de prueba, a continuación se muestra la tabla:

CREATE TABLE USER(
USER_ID INTEGER PRIMARY KEY AUTO_INCREMENT,
USERNAME VARCHAR(100) NOT NULL,
PASSWORD VARCHAR(100) NOT NULL
);

Y la inserción de algunos datos de prueba:

INSERT INTO USER (USERNAME,PASSWORD)VALUES('raidentrance','superSecret');
INSERT INTO USER (USERNAME,PASSWORD)VALUES('john','smith');
INSERT INTO USER (USERNAME,PASSWORD)VALUES('juan','hola123');

Con esto tendremos una tabla para almacenar nuestros registros y una lista de registros de prueba.

3. Creación de entidades

Una vez que el proyecto cuenta con las dependencias necesarias, los siguientes pasos son simples, el primero será crear una entidad que represente la tabla que se creó en nuestra base de datos:


import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author raidentrance
 *
 */
@Entity
@Table(name = "USER")
public class User implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "USER_ID")
	private Integer idUser;

	@Column(name = "USERNAME")
	private String username;

	@Column(name = "PASSWORD")
	private String password;

	private static final long serialVersionUID = -5290198995172316155L;

	public Integer getIdUser() {
		return idUser;
	}

	public void setIdUser(Integer idUser) {
		this.idUser = idUser;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return "User [idUser=" + idUser + ", username=" + username + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((idUser == null) ? 0 : idUser.hashCode());
		result = prime * result + ((username == null) ? 0 : username.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (idUser == null) {
			if (other.idUser != null)
				return false;
		} else if (!idUser.equals(other.idUser))
			return false;
		if (username == null) {
			if (other.username != null)
				return false;
		} else if (!username.equals(other.username))
			return false;
		return true;
	}

}

Esta clase Java será la forma de representar los registros de la base de datos en objetos Java.

4 Creación de Repositorio JPA

Una vez que tenemos la entidad User el siguiente paso es crear un repositorio JPA, para hacerlo solo es necesario crear una interfaz que herede de PagingAndSortingRepository y listo.


import org.springframework.data.repository.PagingAndSortingRepository;

import com.raidentrance.sd.entities.User;

/**
 * @author raidentrance
 *
 */
public interface UserRepository extends PagingAndSortingRepository<User, Integer>{
}

Es importante mencionar que no debemos crear una implementación de la interfaz UserRepository, esto debido a que Spring data la creará por si mismo.

5 Creando clase de aplicación y definiendo las propiedades

El último paso será crear un archivo properties con la información de nuestra base de datos y del api que creamos:

spring.data.rest.basePath=/api

spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_users
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

La propiedad spring.data.rest.basePath representa la url base donde se montarán nuestros servicios.

Por último crearemos la clase aplicación que será la que ejecutaremos para ver nuestras api’s:


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author raidentrance
 *
 */
@SpringBootApplication
public class SpringDataRestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringDataRestApplication.class, args);
    }
}

La clase SpringDataRestApplication será la que ejecutaremos para ver nuestras apis.

6 Analizando la salida

Una vez que ejecutamos la clase SpringDataRestApplication veremos lo siguiente en la url http://localhost:8080/api/users.

{
    "_embedded": {
        "users": [
            {
                "username": "raidentrance",
                "password": "superSecret",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/api/users/1"
                    },
                    "user": {
                        "href": "http://localhost:8080/api/users/1"
                    }
                }
            },
            {
                "username": "john",
                "password": "smith",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/api/users/2"
                    },
                    "user": {
                        "href": "http://localhost:8080/api/users/2"
                    }
                }
            },
            {
                "username": "juan",
                "password": "hola123",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/api/users/3"
                    },
                    "user": {
                        "href": "http://localhost:8080/api/users/3"
                    }
                }
            }
        ]
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/users{?page,size,sort}",
            "templated": true
        },
        "profile": {
            "href": "http://localhost:8080/api/profile/users"
        }
    },
    "page": {
        "size": 20,
        "totalElements": 3,
        "totalPages": 1,
        "number": 0
    }
}

Como podemos ver Spring Data REST creó los servicios para obtener, crear, borrar, etc. información de nuestra base de datos, siguiendo buenas prácticas e implementando HATEAS en unas simples líneas de código.

Si te gusta el contenido y quieres enterarte cuando realicemos un post nuevo síguenos en nuestras redes sociales https://twitter.com/geeks_mx y https://www.facebook.com/geeksJavaMexico/.

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Spring Boot + REST Jersey (Adding Spring Security 4) Part 4


In the previous post we explained how to use HATEOAS step by step using Spring boot Spring Boot + REST Jersey (Adding Spring HATEOAS and MapStruct) Part 3, and we are going to use this project as base to implement Spring Security with basic authentication.

Step 1: Configuration

Spring boot has starter dependencies that are very useful to add new modules to our application, in this example we will add the spring-boot-starter-security dependency as follows:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Step 2: Modifying our Repository

In the post Spring Boot + REST Jersey (Adding Spring HATEOAS and MapStruct) Part 3 we created the repositories UserRepository and RoleRepository. In this example we are going to add a method to UserRepository that will find a user by username.

/**
 *
 */
package com.raidentrance.repositories;

import org.springframework.data.repository.CrudRepository;
import com.raidentrance.entities.User;

/**
 * @author raidentrance
 *
 */
public interface UserRepository extends CrudRepository<User, Integer> {
	User findByUsername(String username);
}

We don’t need to implement the method findByUsername(String username) because Spring data will create the implementation based in a convention.

Step 3: Adding an AuthenticatorService

AuthenticatorService will be the responsible to execute the authentication in the application, the logic will be: Find a user and its role and return it, we don’t need to create a logic to compare users or passwords it will be done by Spring.

/**
 *
 */
package com.raidentrance.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;

/**
 * @author raidentrance
 *
 */
@Service
public class AuthenticatorService implements UserDetailsService {
	@Autowired
	private UserRepository userRepository;

	private static final Logger LOG = LoggerFactory.getLogger(AuthenticatorService.class);

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		LOG.info("Trying to authenticate to {}", username);
		User user = userRepository.findByUsername(username);
		if (user == null) {
			throw new UsernameNotFoundException("Username " + username + " not found");
		} else {
			Collection<? extends GrantedAuthority> authorities = getGrantedAuthorities(user);
			return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities);
		}
	}

	private Collection<? extends GrantedAuthority> getGrantedAuthorities(User user) {
		List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
		list.add(new GrantedAuthority() {
			private static final long serialVersionUID = 2409931876244987359L;
			@Override
			public String getAuthority() {
				return user.getRole().getName();
			}
		});
		return list;
	}
}

Step 4: Configuring Spring security

Once we created the AuthenticatorService we need to define which endpoints do we want to authenticate.

/**
 *
 */
package com.raidentrance.config;

import org.springframework.beans.factory.annotation.Autowired;
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;
import com.raidentrance.service.AuthenticatorService;

/**
 * @author raidentrance
 *
 */
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
	@Autowired
	private AuthenticatorService authenticatorService;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(authenticatorService);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.httpBasic().and().authorizeRequests().anyRequest().authenticated();
	}
}

The method configureGlobal is used to define who is going to search the user, in this example it will use AuthenticatorService previously created.

The method configure is used to define the protected url’s and the authentication mechanism. In this example we are going to use Basic authentication.

Enpoint:  http://localhost:8080/users

Header: Authorization Basic cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0

How to create the header

The value of the header Authorization is created in the following way:

Authorization Basic   :  It is the name of the header and the authentication mechanism

cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0 : This is the value and it is the user:password in base64, in this way it is raidentrance:superSecret in base64.

Testing with CURL

curl http://localhost:8080/users -XGET --user raidentrance:superSecret

Testing with Postman

captura-de-pantalla-2016-09-08-a-las-10-14-35-a-m

captura-de-pantalla-2016-09-08-a-las-10-14-58-a-m

You can find the complete code in the following link : https://github.com/raidentrance/spring-boot-example/tree/part4-adding-security

If you want to learn more about Spring and REST we recommend the following books:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Spring Boot + REST Jersey (Adding Spring HATEOAS and MapStruct) Part 3


In the previous examples we explained the configuration of Spring Boot + REST Jersey Part 1 and Spring Boot + REST Jersey (Adding Spring data) Part 2. Now we are going to take the previous examples as base to show how HATEOAS works by using Spring Boot + Jersey.

Step 1: Configuration

Spring boot has starter dependencies that are very useful to add new modules to our application, in this example we will add the spring-hateoas dependency as follows:

<dependency>
    <groupId>org.springframework.hateoas</groupId>
    <artifactId>spring-hateoas</artifactId>
</dependency>

Step 2: Adding entities

In the previous example we learned how to use Spring data to get information from a database and how to use Spring Jersey to expose this information in a web service. In this example we created the entity User, now we are going to create a new entity named Role.

/**
 *
 */
package com.raidentrance.entities;

import java.io.Serializable;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

/**
 * @author raidentrance
 *
 */
@Entity
@Table(name = "ROLE")
public class Role implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID_ROLE")
    private Integer idRole;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "NAME")
    private String name;

    @Size(max = 100)
    @Column(name = "DESCRIPTION")
    private String description;

    private static final long serialVersionUID = 3428234636660051311L;

    ........
}

And we are going to modify the entity User.

/**
 *
 */
package com.raidentrance.entities;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * @author raidentrance
 *
 */
@Entity
@Table(name ="USER")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "USER_ID")
    private Integer idUser;

    @Column(name = "USERNAME")
    private String username;

    @Column(name = "PASSWORD")
    private String password;

    @JoinColumn(name = "ROLE_ID", referencedColumnName = "ID_ROLE")
    @ManyToOne(optional = false)
    private Role role;
.....
}

Step 3: Updating the sql scripts

As we created a new entity we are going to need a new table to store the information, in the previous example we created 2 files schema.sql and init.sql, they contain the scripts to create the tables and to fill the data.

schema.sql

CREATE TABLE ROLE(
ID_ROLE INTEGER PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(45) NOT NULL ,
DESCRIPTION VARCHAR(100) NULL
);

CREATE TABLE USER(
USER_ID INTEGER PRIMARY KEY AUTO_INCREMENT,
USERNAME VARCHAR(100) NOT NULL,
PASSWORD VARCHAR(100) NOT NULL,
ROLE_ID INTEGER NOT NULL,
    FOREIGN KEY (ROLE_ID)
    REFERENCES ROLE (ID_ROLE)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

init.sql

INSERT INTO ROLE (NAME,DESCRIPTION)VALUES("ADMIN","Administrator");
INSERT INTO ROLE (NAME,DESCRIPTION)VALUES("USER","Normal user");

INSERT INTO USER (USERNAME,PASSWORD,ROLE_ID)VALUES('raidentrance','superSecret',1);
INSERT INTO USER (USERNAME,PASSWORD,ROLE_ID)VALUES('john','smith',1);
INSERT INTO USER (USERNAME,PASSWORD,ROLE_ID)VALUES('juan','hola123',2);

HATEOAS is the abbreviation of Hypermedia as the Engine of Application state and it will allow to navigate across all the REST resources without any documentation, in this way each of the resources will return a link to its resource.

Step 4: Creating DTO’s with HATEOAS support

Now we have to create Dto’s to support the links generated by HATEOAS by extending of the class ResourceSupport.

/**
 *
 */
package com.raidentrance.dto;

import java.io.Serializable;
import org.springframework.hateoas.ResourceSupport;

/**
 * @author raidentrance
 *
 */
public class RoleDto extends ResourceSupport implements Serializable {

    private Long idRole;

    private String name;

    private String description;

    ........

}
/**
 *
 */
package com.raidentrance.dto;

import java.io.Serializable;
import org.springframework.hateoas.ResourceSupport;
import com.raidentrance.entities.Role;

/**
 * @author raidentrance
 *
 */
public class UserDto extends ResourceSupport implements Serializable {

    private Long idUser;

    private String username;

    private String password;

    private RoleDto role;

..........
}

As you can see the Dto’s extends from the class ResourceSupport, it allows to have support to include links to the resources.

Step 5: Creating an Abstract Assembler

The next step is create an abstract assembler, this will be useful to generate the links to the resources.

/**
 *
 */
package com.raidentrance.assembler;

import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.jaxrs.JaxRsLinkBuilder;
import org.springframework.hateoas.mvc.ResourceAssemblerSupport;

import jersey.repackaged.com.google.common.base.Preconditions;

/**
 * @author raidentrance
 *
 */
public abstract class JaxRsResourceAssemblerSupport<T, D extends ResourceSupport>
        extends ResourceAssemblerSupport<T, D> {
    private final Class<?> controllerClass;

    public JaxRsResourceAssemblerSupport(Class<?> controllerClass, Class<D> resourceType) {

        super(controllerClass, resourceType);
        this.controllerClass = controllerClass;
    }

    @Override
    protected D createResourceWithId(Object id, T entity, Object... parameters) {
        Preconditions.checkNotNull(entity);
        Preconditions.checkNotNull(id);
        D instance = instantiateResource(entity);
        instance.add(JaxRsLinkBuilder.linkTo(controllerClass).slash(id).withSelfRel());
        return instance;
    }
}

Step 6: Creating a mapper

Now we are going to create a mapper to transform from JPA entities to Dto’s, in order to do it we will use MapStruct.

/**
 *
 */
package com.raidentrance.mapper;

import org.mapstruct.Mapper;
import com.raidentrance.dto.RoleDto;
import com.raidentrance.dto.UserDto;
import com.raidentrance.entities.Role;
import com.raidentrance.entities.User;

/**
 * @author raidentrance
 *
 */

@Mapper
public interface UserMapper {
    UserDto userEntityToUser(User entity);

    User userToUserEntity(UserDto dto);

    RoleDto roleEntityToRole(Role entity);

    Role roleToRoleEntity(RoleDto role);
}

Step 7: Adding endpoints

The first step will be create the resource for “users” and “roles”, in the following steps we will explain how to implement each method.
UserResource.java

/**
 *
 */
package com.raidentrance.resource;

import java.util.ArrayList;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;
import jersey.repackaged.com.google.common.collect.Lists;

/**
 * @author raidentrance
 *
 */

@Component
@Path("/users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {

    ......
}

RoleResource.java

/**
 *
 */
package com.raidentrance.resource;

import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * @author raidentrance
 *
 */
@Component
@Path("/roles")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class RoleResource {
......
}

Step 8: Registering the endpoints

Like in the previous examples we need to register each resource in Jersey.

/**
 *
 */
package com.raidentrance.config;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;

import com.raidentrance.resource.RoleResource;
import com.raidentrance.resource.UserResource;

/**
 * @author raidentrance
 *
 */
@Component
public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
         register(UserResource.class);
         register(RoleResource.class);
    }
}

Step 9: Creating assemblers

Now we have to create the assemblers, these components will be responsible to transform from Entities to Dto’s and to include the links generated by HATEOS.

RoleAssembler.java

/**
 *
 */
package com.raidentrance.assembler;

import org.mapstruct.factory.Mappers;
import org.springframework.stereotype.Component;
import com.raidentrance.dto.RoleDto;
import com.raidentrance.entities.Role;
import com.raidentrance.mapper.UserMapper;
import com.raidentrance.resource.RoleResource;

/**
 * @author raidentrance
 *
 */
@Component
public class RoleAssembler extends JaxRsResourceAssemblerSupport<Role, RoleDto> {

    private UserMapper mapper = Mappers.getMapper(UserMapper.class);

    public RoleAssembler() {
        super(RoleResource.class, RoleDto.class);
    }

    @Override
    public RoleDto toResource(Role entity) {
        RoleDto role = createResourceWithId(entity.getIdRole(), entity);
        RoleDto result = mapper.roleEntityToRole(entity);
        result.add(role.getLinks());
        return result;
    }
}

UserAssembler.java

/**
 *
 */
package com.raidentrance.assembler;

import org.mapstruct.factory.Mappers;
import org.springframework.beans.factory.annotation.Autowired;
import com.raidentrance.dto.RoleDto;
import com.raidentrance.dto.UserDto;
import com.raidentrance.entities.User;
import com.raidentrance.mapper.UserMapper;
import com.raidentrance.resource.UserResource;

/**
 * @author raidentrance
 *
 */
@Component
public class UserAssembler extends JaxRsResourceAssemblerSupport<User, UserDto> {
    @Autowired
    private RoleAssembler assembler;

    private UserMapper mapper = Mappers.getMapper(UserMapper.class);

    public UserAssembler() {
        super(UserResource.class, UserDto.class);
    }

    @Override
    public UserDto toResource(User entity) {
        UserDto resource = createResourceWithId(entity.getIdUser(), entity);
        UserDto result = mapper.userEntityToUser(entity);
        RoleDto role = assembler.toResource(entity.getRole());
        result.add(resource.getLinks());
        result.setRole(role);
        return result;
    }
}

Step 10: Adding the repository to the entity Role

As we are using Spring data, it is necessary to create the repository of the entity Role in order to be able to get the data from the database.

/**
 *
 */
package com.raidentrance.repositories;

import org.springframework.data.repository.CrudRepository;

import com.raidentrance.entities.Role;

/**
 * @author raidentrance
 *
 */
public interface RoleRepository extends CrudRepository<Role, Integer>{

}

Step 11: Completing the endpoints

Now we are going to add the missing code to the endpoints that we have created.

UserResource.java

/**
 *
 */
package com.raidentrance.resource;

import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.raidentrance.assembler.UserAssembler;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;
import jersey.repackaged.com.google.common.collect.Lists;

/**
 * @author raidentrance
 *
 */

@Component
@Path("/users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {

    @Autowired
    private UserAssembler userAssembler;

    @Autowired
    private UserRepository userRepository;

    @GET
    public Response getUsers() {
        List<User> users = Lists.newArrayList(userRepository.findAll());
        return Response.ok(userAssembler.toResources(users)).build();
    }

    @GET
    @Path("/{idUser}")
    public Response getById(@PathParam("idUser") Integer idUser) {
        User requested = userRepository.findOne(idUser);
        return Response.ok(userAssembler.toResource(requested)).build();
    }

}

RoleResource.java

/**
 *
 */
package com.raidentrance.resource;

import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.raidentrance.assembler.RoleAssembler;
import com.raidentrance.entities.Role;
import com.raidentrance.repositories.RoleRepository;
import jersey.repackaged.com.google.common.collect.Lists;

/**
 * @author raidentrance
 *
 */
@Component
@Path("/roles")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class RoleResource {

    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private RoleAssembler assembler;

    @GET
    public Response getRoles() {
        List<Role> role = Lists.newArrayList(roleRepository.findAll());
        return Response.ok(assembler.toResources(role)).build();
    }

    @GET
    @Path("/{idRole}")
    public Response getById(@PathParam("idRole") Integer idRole) {
        Role requested = roleRepository.findOne(idRole);
        return Response.ok(assembler.toResource(requested)).build();
    }
}

Step 12: Compile the application

As we are using MapStruct we need to generate the Mappers, in order to do it we have to execute the command mvn generate-sources, once the mappers are created we are ready to compile the application by using the command mvn clean install.

Step 13: Testing all together

The last step is to execute the class SprinBootSampleApplication and access to the following urls:

Open the url http://localhost:8080/users

[
{
idUser: 1,
username: "raidentrance",
password: "superSecret",
role: {
idRole: 1,
name: "ADMIN",
description: "Administrator",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/1"
}
]
},
links: [
{
rel: "self",
href: "http://localhost:8080/users/1"
}
]
},
{
idUser: 2,
username: "john",
password: "smith",
role: {
idRole: 1,
name: "ADMIN",
description: "Administrator",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/1"
}
]
},
links: [
{
rel: "self",
href: "http://localhost:8080/users/2"
}
]
},
{
idUser: 3,
username: "juan",
password: "hola123",
role: {
idRole: 2,
name: "USER",
description: "Normal user",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/2"
}
]
},
links: [
{
rel: "self",
href: "http://localhost:8080/users/3"
}
]
}
]

http://localhost:8080/users/1

{
idUser: 1,
username: "raidentrance",
password: "superSecret",
role: {
idRole: 1,
name: "ADMIN",
description: "Administrator",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/1"
}
]
},
links: [
{
rel: "self",
href: "http://localhost:8080/users/1"
}
]
}

http://localhost:8080/roles

[
{
idRole: 1,
name: "ADMIN",
description: "Administrator",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/1"
}
]
},
{
idRole: 2,
name: "USER",
description: "Normal user",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/2"
}
]
}
]

http://localhost:8080/roles/1

{
idRole: 1,
name: "ADMIN",
description: "Administrator",
links: [
{
rel: "self",
href: "http://localhost:8080/roles/1"
}
]
}

If you want to learn more about web services we recommend the following books:

You can find the complete code in the following link https://github.com/raidentrance/spring-boot-example/tree/part3-adding-hateoas

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Spring Boot + REST Jersey (Adding Spring data) Part 2


In this post, I will explain in an easy way how to configure and use Spring data with Spring boot. In order to do it we will use a previous example Spring Boot + REST Jersey Part 1.

Step 1 (Including maven dependencies)

Spring boot generated starter dependencies, this dependencies contain all the necessary resources to use each of the spring modules in the easiest way. The versions of the necessary dependencies are not required because they come from the spring boot parent project. To configure Spring Data is necessary add the following dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

Step 2 (Configuring the datasource)

The next step will be create a file named application.properties, in this file we will define the information of the database connection, in this example we will show how to create a datasource for MySQL.

spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_users
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

In the file application.properties is possible to define multiples configurations for spring boot like database information, ports, context path, etc. This file can be a .properties or a .yml file.

Step 3 (Configuring repositories)

Spring Data uses repositories to access to the information, now we have to define the java package that will contain all the repositories, in this example will be com.raidentrance.repositories.

/**
 *
 */
package com.raidentrance.config;

import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author raidentrance
 *
 */
@EnableTransactionManagement
@EnableJpaRepositories("com.raidentrance.repositories")
public class SpringDataConfig {

}

Step 4 (Creating the tables and data for the example)

The application will use a table named user with the following structure:

CREATE TABLE USER(
USER_ID INTEGER PRIMARY KEY AUTO_INCREMENT,
USERNAME VARCHAR(100) NOT NULL,
PASSWORD VARCHAR(100) NOT NULL
);

Now we have to insert some sample data:

INSERT INTO USER (USERNAME,PASSWORD)VALUES('raidentrance','superSecret');
INSERT INTO USER (USERNAME,PASSWORD)VALUES('john','smith');
INSERT INTO USER (USERNAME,PASSWORD)VALUES('juan','hola123');

Step 6 (Creating JPA entities)

Once we configured Spring Data, created the tables and populated them we have to create a JPA entity to represent the relational model in the domain model by creating the entity User.java.

/**
 *
 */
package com.raidentrance.entities;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author raidentrance
 *
 */
@Entity
@Table(name = "USER")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "USER_ID")
    private Integer idUser;

    @Column(name = "USERNAME")
    private String username;

    @Column(name = "PASSWORD")
    private String password;

    private static final long serialVersionUID = -5290198995172316155L;

    public Integer getIdUser() {
        return idUser;
    }

    public void setIdUser(Integer idUser) {
        this.idUser = idUser;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [idUser=" + idUser + ", username=" + username + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((idUser == null) ? 0 : idUser.hashCode());
        result = prime * result + ((username == null) ? 0 : username.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (idUser == null) {
            if (other.idUser != null)
                return false;
        } else if (!idUser.equals(other.idUser))
            return false;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }

}

Step 7 (Creating a Spring data repository)

Now we have to create a Spring data repository, this will be used to access to the database:

/**
 *
 */
package com.raidentrance.repositories;

import org.springframework.data.repository.CrudRepository;

import com.raidentrance.entities.User;

/**
 * @author raidentrance
 *
 */
public interface UserRepository extends CrudRepository<User, Integer> {
}

UserRepository is an interface, the most common question is, do I have to create a class that implements the UserRepository interface ? the answer is NO, the only thing that we need to do is to define the interface and Spring Data will create the implementation for it.

Step 8 (Using the JPA Repository)

The last part is to use the repository in the application, in order to do it, we will integrate the component in the web service REST created in the part 1 of the tutorial Spring Boot + REST Jersey Part 1.

/**
 *
 */
package com.raidentrance.resource;

import java.util.ArrayList;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;
import jersey.repackaged.com.google.common.collect.Lists;

/**
 * @author raidentrance
 *
 */

@Component
@Path("/users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {

    @Autowired
    private UserRepository userRepository;

    @GET
    public Response getUsers() {
        ArrayList<User> users = Lists.newArrayList(userRepository.findAll());
        return Response.ok(users).build();
    }

}

In order to use the repository created we will use the annotation @Autowired, as you can see the method used to get all the users is findAll(), this method is not defined in the interface created, it is defined in the parent interface named CrudRepository.

Step 9 (Testing all together)

In order to test the project the only thing you need to do is execute the class SpringBootSampleApplication, when it finishes you have to execute the endpoint http://localhost:8080/users.

Output

[
{
idUser: 1,
username: "raidentrance",
password: "superSecret"
},
{
idUser: 2,
username: "john",
password: "smith"
},
{
idUser: 3,
username: "juan",
password: "hola123"
}
]

Next steps

In the following posts we will explain:

  • How to return a DTO instead of a list of entities in the web service REST
  • Add ExceptionMappers for error handling
  • Add support for HATEOAS
  • Add spring security
  • Add logging
  • Add different profiles for different environments

You can find the complete code in the following link https://github.com/raidentrance/spring-boot-example/tree/part2-adding-springdata

If you want to learn more about web services we recommend the following books:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

How to create a RESTful web application in minutes with JHipster (Spring Boot + AngularJS )


JHipster is an scaffolding tool developed by Yeoman and used to develop Spring Boot + AngularJS projects. The present post intends to guide you on how to create a new web application step by step.

Installing JHipster

Before starting with our application, you must be sure that you cover the following requirements:

  • Install and configure Java 8 on your system.
  • Install Node-js from its website, this will also install npm.
  • Install Yeoman using npm install –g yo.
  • Install Bower using npm install –g bower.
  • Install Gulp using npm install –g gulp-cli.
  • Install JHipster using npm install –g generator-jhipster.

With this simple steps JHipster has been successfully installed.

Creating an application

Once you have JHipster installed in your system, follow the next steps to create your new application.

  • Create an empty directory where the project is going to be allocated.
    mkdir jhipster-example
  • Go to the new directory.
    cd jhipster-example
  • Create a new application using the following command:
    yo jhipster
  •  JHipster will ask for authorization to send anonymously a report of usage statistics, you can decide this according to your preference.
  • The type of application you want to create, for this post we will choose Monolithic application.

  • Application name:
    • raidentrance
  • Base package name:
    • com.raidentrance.jhipster
  • Authentication type:
    • HTTP Session Authentication (stateful, default Spring Security Mechanism).
  • Data Base type:
    • SQL
  • Data Base to be used in production:
    • MySQL
  • Data Base to be used in development:
    • MySQL
  • Are you planning to use a second layer of cache on Hibernate?:
    • Yes, with ehcache (local cache for a single node).
  • Building tool:
    • Maven
  • Additional Tools:
    • None
  •  Use LibSass for CSS files processing:
    • Yes
  • Internationalization Support:
    • No. (By saying yes you will have to choose a native language and then additional languages you would like to install).
  • Testing framework:
    • Gatling
  • Override .gitignore file:
    • Yes

Once you are done with the initial configuration JHipster will generate the complete application displaying the following message:

Running the application

Up to now we should have a full project ready to be configured, compiled and run. To do this, we require some additional steps:

  • Compile the project using mvn clean install.
  • Create an empty data base for the project.
  • Modify the project configurations in the file application-dev.yml located on src/main/resources/config, in this post you have to fill the DB Url, DB User and password.
  • To execute the project you can run inside your IDE the RaidentranceApp.java as Spring Boot Application or you can use the command mvn spring-boot:run

Now you will be able to open a browser and look for http://127.0.0.1:8080 to retrieve the Welcome page from JHipster containing: In the top-left corner the profile that is being used (dev) and an account tab to register new users or use an existent account.

By default JHipster will generate an admin user with password admin, once you are authenticated you should see the following screen:

This screen will contain different sections described below:

  • Entities: here you will see the entities defined for the project, at the very beginning this is going to be empty since we haven’t created anyone.
  • Account:
    • Settings: Used to modify the username, last name and e-mail.
    • Password: Used to change the current user password.
    • Sessions: Shows the active sessions.
    • Sign Out.
  • Administration:
    • User management: Will allow you to view an modify your user accounts.
    • Metrics: Shows application metrics such as the number of http requests, use of the REST web services, cache and use of datasource.
  • Health: Shows the checks defined by the application.
  • Configuration: Shows all the current configurations for the application.
  • Audits: Allows you to enable and check entity audits.
  • Logs: Used to change the log levels on the application.
  • API: Shows the web services in the application together with a brief description on how to use each one of them.

All the features showed were created following development best practices by only executing one command and completing a quick wizard.

On the next post we will explain how to create new Web Pages , the idea will be to create a complete application piece by piece and in just a couple of minutes.

Author: Alejandro Agapito Bautista

Twitter: @raidentrance

Contact:raidentrance@gmail.com

Translated By: Oscar Camacho – melchior01

Contact: adamfirstangel@hotmail.com

Crea una aplicación Web+REST (Spring boot + AngularJS) en minutos utilizando JHipster


JHipster es una herramienta de Scaffolding creada por Yeoman utilizada para crear proyectos utilizando Spring Boot + AngularJs.

Instalación

Antes de iniciar con la creación de las aplicaciones debemos asegurarnos que tenemos el ambiente de trabajo instalado y configurado correctamente. Para esto debemos seguir los siguientes pasos:

  • Instalar y configurar la versión 8 de Java
  • Instalar Node.js del sitio web, esto instalará el comando npm.
  • Instalar Yeoman utilizando el comando npm install -g yo 
  • Instalar Bower utilizando el comando npm install -g bower
  • Instalar Gulp utilizando el comando npm install -g gulp-cli
  • Instalar JHipster utilizando el comando npm install -g generator-jhipster

Con estos sencillos pasos JHipster ha sido instalado de forma exitosa.

Creando una aplicación en minutos utilizando JHipster

Una vez instalado JHipster el siguiente paso es crear una aplicación para esto seguiremos los siguientes pasos:

  • Crear una carpeta vacía la cuál contendrá el proyecto que se genere:
mkdir jhipster-example
  • Ir al directorio creado utilizando:
cd jhipster-example
  • Crear la aplicación utilizando el comando:
yo jhipster

JHipster preguntará por  lo siguiente:

  • Permiso para utilizar estadísticas de uso.
  • El tipo de aplicación que se desea construir como se muestra en la imagen:
    • Monolithic application

captura-de-pantalla-2016-09-29-a-las-9-00-07-a-m

  • El nombre de la aplicación
    • raidentrance
  • Nombre del paquete base
    • com.raidentrance.jhipster
  • Tipo de autenticación que se desea utilizar,
    • HTTP Session Authentication (stateful, default Spring Security mechanism)

  • Tipo de base de datos  a utilizar
    • SQL
  • Base de datos a utilizar en producción
    •  MySQL
  • Base de datos a utilizar en desarrollo
    • MySQL
  • Si se utilizará el segundo nivel de cache de Hibernate
    • Yes, with ehcache (local cache, for a single node)

  • Herramienta para construcción del proyecto
    • para nuestro ejemplo utilizaremos Maven.
  • Herramientas adicionales
    • No se selecciona ninguna opción
  • Utilizar LibSass para el procesamiento de CSS
    • Yes
  • Soporte para internacionalización
    • No
  • Framework de testing a utilizar
    • Gatling
  • Sobre escribir el archivo .gitignore
    • Si

Con estos pasos JHipster generará la aplicación completa y mostrará el siguiente mensaje:

captura-de-pantalla-2016-09-29-a-las-9-09-49-a-m

Iniciar la aplicación

Una vez creado el proyecto el siguiente paso es iniciar la aplicación, para esto se deben seguir los siguientes pasos:

  • Compilar el proyecto con maven utilizando el comando mvn clean install
  • Crear una base de datos vacía para el proyecto
  • Modificar configuraciones del proyecto, para esto abriremos el archivo application-dev.yml ubicado en src/main/resources/config.Para este ejemplo se modificará lo siguiente:
    • URL de la base de datos
    • Usuario de la base de datos
    • Password de la base de datos
  • Para ejecutar el proyecto es posible hacer lo siguiente:
    • Ejecutar en el IDE la clase RaidentranceApp.java como Spring boot application
    • Utilizar el plugin de Spring boot con el comando mvn spring-boot:run
  • Abrir en el navegador la dirección http://127.0.0.1:8080. Se mostrará lo siguiente:

 

Captura de pantalla 2016-09-29 a las 12.25.30 p.m..png

Puntos a analizar:

  • En la parte superior izquierda muestra que se está utilizando el perfil dev
  • En la pestaña de Account se tiene la posibilidad de registrar a un usuario nuevo o autenticar uno existente.
  • Al seleccionar Sign in se mostrará lo siguiente

Captura de pantalla 2016-09-29 a las 12.27.23 p.m..png

  • Por default en desarrollo JHipster crea un usuario llamado admin con el password admin, al autenticarte se mostrará la siguiente página de bienvenida:

 

Captura de pantalla 2016-09-29 a las 12.23.47 p.m..png

  • En la sección entities se mostrarán las entidades propias del proyecto, en este momento no ha creado ninguna por lo que aparecerá vacía.
  • Account muestra lo siguiente:
    • Settings: Permite modificar nombre, apellido y correo electrónico
    • Password: Permite cambiar el password del usuario autenticado
    • Sessions: Muestra las sesiones activas del usuario
    • Sign out: Permite cerrar sesión en la aplicación
  • Administración muestra lo siguiente:
    • User management: Permite llevar acabo la administración de usuarios de la aplicación
    • Metrics: Muestra métricas de la aplicación, por ejemplo (número de peticiones http, estadísticas de uso de los web services REST, estadísticas de uso de cache y estadísticas de uso del datasource)
  • Health muestra lo siguiente:
    • Muestra los health checks definidos en la aplicación
  • Configuration
    • Muestra todas las configuraciones de la aplicación
  • Audits
    • Muestra los registros para hacer auditoría en el sistema
  • Logs
    • Muestra y permite cambiar los niveles de log de la aplicación
  • API
    • Muestra los web services de la aplicación así como una explicación de como utilizarlos como se muestra en la siguiente imagen

Captura de pantalla 2016-09-29 a las 12.37.41 p.m..png

Toda la funcionalidad mostrada fue creada siguiendo buenas prácticas de desarrollo solo ejecutando un solo comando y llenando un wizard sencillo.

En el siguiente POST se explicará cómo crear nuevas páginas en minutos, la idea será crear una aplicación completa en minutos.

Subiré el código completo en el siguiente post con el fin de que esté completo.

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

 

Spring Boot + REST Jersey (Agregando Spring Security 4) Parte 4


En el último post se explicó paso a paso la configuración de HATEOAS utilizando Spring boot Spring Boot + REST Jersey (Agregando Spring Hateoas y Dto) Parte 3, se tomará ese proyecto como base. Ahora se explicará de forma simple la configuración de Spring security, para este ejemplo se utilizará Basic authentication.

1. Configuración, Spring boot generó starter dependencies, estas dependencias contienen todos los recursos necesarios para utilizar el módulo de spring deseado de una forma simple y manejable de una forma más simple, las versiones de estas dependencias no son requeridas ya que se heredan del proyecto padre de spring boot. Para configurar Spring Security se requiere agregar la siguiente dependencia:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

2.Modificando nuestro repositorio, En el post Spring Boot + REST Jersey (Agregando Spring Hateoas y Dto) Parte 3 se crearon los repositorios UserRepository y RoleRepository. En este ejemplo se agregará un método a UserRepository que realizará una búsqueda de usuario por username.

/**
 *
 */
package com.raidentrance.repositories;

import org.springframework.data.repository.CrudRepository;
import com.raidentrance.entities.User;

/**
 * @author raidentrance
 *
 */
public interface UserRepository extends CrudRepository<User, Integer> {
	User findByUsername(String username);
}

No se debe realizar ninguna implementación de findByUsername, Spring data detectará en base a convención que se desea buscar un objeto Usuario a través del atributo username y realizará la implementación.

3. Agregando AuthenticatorService, AuthenticatorService será el responsable de realizar la autenticación en la aplicación, de tal modo que la lógica de esta clase será buscar al usuario en la base de datos así como su rol y devolverlo, la comparación entre el usuario y la contraseña enviada con lo que este autenticator devuelve será realizada por Spring.

/**
 *
 */
package com.raidentrance.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;

/**
 * @author raidentrance
 *
 */
@Service
public class AuthenticatorService implements UserDetailsService {
	@Autowired
	private UserRepository userRepository;

	private static final Logger LOG = LoggerFactory.getLogger(AuthenticatorService.class);

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		LOG.info("Trying to authenticate to {}", username);
		User user = userRepository.findByUsername(username);
		if (user == null) {
			throw new UsernameNotFoundException("Username " + username + " not found");
		} else {
			Collection<? extends GrantedAuthority> authorities = getGrantedAuthorities(user);
			return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities);
		}
	}

	private Collection<? extends GrantedAuthority> getGrantedAuthorities(User user) {
		List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
		list.add(new GrantedAuthority() {
			private static final long serialVersionUID = 2409931876244987359L;
			@Override
			public String getAuthority() {
				return user.getRole().getName();
			}
		});
		return list;
	}
}

4. Configurando Spring security,el siguiente paso es configurar los endpoints que serán protegidos así como el mecanismo de autenticación a utilizar.

/**
 *
 */
package com.raidentrance.config;

import org.springframework.beans.factory.annotation.Autowired;
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;
import com.raidentrance.service.AuthenticatorService;

/**
 * @author raidentrance
 *
 */
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
	@Autowired
	private AuthenticatorService authenticatorService;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(authenticatorService);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.httpBasic().and().authorizeRequests().anyRequest().authenticated();
	}
}

El método configureGlobal es utilizado para definir quién va a realizar la búsqueda de los usuarios, para este ejemplo se utilizará  el AuthenticatorService creado previamente.

El método configure es utilizado para definir las url a las que se realizará la autenticación y que mecanismo se utilizará. En este caso al ser servicios web se realiza Basic authentication pero no es el único.

Enpoint:  http://localhost:8080/users

Header: Authorization Basic cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0

El valor header Authorization está compuesto del siguiente modo

Authorization Basic   : Nombre del header y tipo de autenticación.

cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0 : Valor, está compuesto del siguiente modo.

raidentrance:superSecret En base 64 de tal modo que :

raidentrance=username

superSecret=password

Probando utilizando CURL:

curl http://localhost:8080/users -XGET --user raidentrance:superSecret

Probando utilizando Postman

captura-de-pantalla-2016-09-08-a-las-10-14-35-a-m

captura-de-pantalla-2016-09-08-a-las-10-14-58-a-m

Puedes encontrar el código completo del ejemplo en el siguiente enlace:

https://github.com/raidentrance/spring-boot-example/tree/part4-adding-security

 

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com