20. Beveiliging van de webservice voor toegang tot de database [dbproduitscategories]
20.1. Het opzetten van de werkomgeving
We zullen de beveiliging van de webservice implementeren met de volgende projecten:
![]() |
- de projecten [spring-security-*] zijn te vinden in de map [<exemples>\spring-database-generic\spring-security];
- de beveiliging wordt geïmplementeerd voor SGBD en MySQL met een laag [DAO / JDBC] en vervolgens een laag [DAO / JPA / Hibernate];
- druk op Alt-F5 en genereer vervolgens alle Maven-projecten opnieuw;
We moeten gebruikers aanmaken in de database [dbproduitscategories]. Gebruik hiervoor de uitvoerconfiguratie [spring-security-create-users-hibernate-eclipselink]:
![]() | ![]() |
Door deze configuratie uit te voeren, worden de tabellen [USERS, ROLES, USERS_ROLES] gevuld vanuit de tabel [dbproduitscategories]:
![]() |
![]() |
De aangemaakte gebruikersnamen [login/passwd] zijn de volgende: [admin/admin], [user/user], [guest/guest]. In de database zijn de wachtwoorden versleuteld.
![]() |

Voer vervolgens de uitvoeringsconfiguratie met de naam [spring-security-server-jpa-generic-hibernate-eclipselink] uit, waarmee de beveiligde webservice wordt gestart (MySQL moet al zijn gestart):
![]() | ![]() |
Voer vervolgens de uitvoeringsconfiguratie met de naam [spring-security-client-generic-JUnitTestDao] uit, waarmee de beveiligde webservice wordt getest:
![]() | ![]() |
De test moet slagen.
20.2. Het Eclipse-project [spring-security-server-jdbc-generic]
De beveiligde webservice wordt geïmplementeerd door het project [spring-security-server-jdbc-generic]:
![]() |
Hierboven:
- de laag [DAO1] is de laag [DAO] die de tabellen [PRODUITS] en [CATEGORIES] van de database [dbproduitscategories] beheert. Deze is al geschreven;
- de laag [DAO2] is de laag [DAO] die de tabellen [USERS], [ROLES] en [USERS_ROLES] van de database [dbproduitscategories] beheert. Deze moet nog worden geschreven;
![]() |
20.2.1. De Maven-configuratie
Het project [spring-security-server-jdbc-generic] is een Maven-project dat wordt geconfigureerd door het volgende bestand [pom.xml]:
<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>dvp.spring.database</groupId>
<artifactId>spring-security-server-jdbc-generic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-server-jdbc-generic</name>
<description>démo spring security</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- webserver / jSON -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>spring-webjson-server-jdbc-generic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<!-- plug-ins -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- regels 29-33: we nemen de bestaande configuratie over met het archief van de onderzochte webservice / json / jdbc;
- regels 24-27: de afhankelijkheid die de klassen van Spring Security toevoegt;
Uiteindelijk vertoont het project de volgende afhankelijkheden ten opzichte van de andere projecten die in Eclipse zijn geladen:
![]() |
20.2.2. De laag [DAO2]
![]() |
Hierboven:
- de laag [DAO1] is de laag [DAO] die de tabellen [PRODUITS] en [CATEGORIES] van de database [dbproduitscategories] beheert. Deze is al geschreven;
- de laag [DAO2] is de laag [DAO] die de tabellen [USERS], [ROLES] en [USERS_ROLES] van de database [dbproduitscategories] beheert. Dit is de laag die we nu gaan schrijven;
![]() |
Spring Security vereist dat er een klasse wordt aangemaakt die de volgende interface [UsersDetail] implementeert:
![]() |
Deze interface wordt hier geïmplementeerd door de klasse [AppUserDetails]:
package spring.security.dao;
import generic.jdbc.config.ConfigJdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import spring.jdbc.entities.Role;
import spring.jdbc.entities.User;
import spring.jdbc.infrastructure.DaoException;
public class AppUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
// JdbcTemplate
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
// eigenschappen
private User user;
private String simpleClassName = getClass().getSimpleName();
// bouwers
public AppUserDetails() {
}
public AppUserDetails(User user, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.user = user;
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
// -------------------------interface
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : getRoles(user.getId())) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
...
// privé-methoden----------------
private List<Role> getRoles(Long id) {
try {
// de gebruiker opzoeken via zijn id
return namedParameterJdbcTemplate.query(ConfigJdbc.SELECT_ROLES_BYUSERID, Collections.singletonMap("id", id), new ShortRoleMapper());
} catch (Exception e) {
//e.printStackTrace();
throw new DaoException(167, e, simpleClassName);
}
}
}
// --------------------- mappers
class ShortRoleMapper implements RowMapper<Role> {
@Override
public Role mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Role(rs.getLong("r_ID"), rs.getLong("r_VERSIONING"), rs.getString("r_NAME"));
}
}
- regel 22: de klasse [AppUserDetails] implementeert de interface [UserDetails];
- regels 29-30: de klasse kapselt een gebruiker in (regel 19) en de repository waarmee de gegevens van deze gebruiker kunnen worden opgehaald (regel 20);
- regel 27: de database wordt benaderd via JDBC met behulp van het object [NamedParameterJdbcTemplate namedParameterJdbcTemplate] dat is gedefinieerd in het project [spring-jdbc-generic-04]. Merk op dat dit object niet door Spring wordt geïnjecteerd, zoals vaak het geval was. Het wordt doorgegeven aan de constructor in de regels 36-39. Waarom? Omdat de klasse [AppUserDetails] geen Spring-component is (de annotatie @Component ontbreekt) en er dus geen injecties in kunnen plaatsvinden;
- regels 36-39: de constructor die de klasse instantiëert met een gebruiker en diens repository;
- regels 42-49: implementatie van de methode [getAuthorities] van de interface [UserDetails]. Deze moet een verzameling elementen van het type [GrantedAuthority] of een afgeleid type samenstellen. Hier gebruiken we het afgeleide type [SimpleGrantedAuthority] (regel 46) dat de naam van een van de rollen van de gebruiker uit regel 29 omvat;
- regels 45-47: we doorlopen de lijst met rollen van de gebruiker uit regel 29 om een lijst met elementen van het type [SimpleGrantedAuthority] samen te stellen;
- regel 45: om de rollen van de gebruiker op te halen, wordt de privémethode [getRoles] uit regel 53 gebruikt;
- regel 56: voert de volgende opdracht SQL [ConfigJdbc.SELECT_ROLES_BYUSERID] (gedefinieerd in [Configjdbc]) uit:
public static final String SELECT_ROLES_BYUSERID = "SELECT DISTINCT r.ID as r_ID, r.VERSIONING as r_VERSIONING, r.NAME as r_NAME FROM ROLES r, USERS u, USERS_ROLES ur WHERE u.ID=:id AND ur.USER_ID=u.ID AND ur.ROLE_ID=r.ID";
Deze query SQL voert een join uit tussen de drie tabellen [USERS, ROLES, USERS_ROLES] om de rollen te verkrijgen van een gebruiker die wordt geïdentificeerd aan de hand van zijn primaire sleutel. De query wordt geconfigureerd met de primaire sleutel [:id] van de gebruiker waarvan de rollen worden opgezocht.
- regel 56: elke resultaatregel van de [SELECT] wordt omgezet in een entiteit [Role] door de klasse [ShortRowMapper] in de regels 66-72;
Laten we teruggaan naar de code van de klasse [AppUserDetails]:
package spring.security.dao;
...
public class AppUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
// JdbcTemplate
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
// eigenschappen
private User user;
private String simpleClassName = getClass().getSimpleName();
// constructors
public AppUserDetails() {
}
public AppUserDetails(User user, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.user = user;
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
// -------------------------interface
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : getRoles(user.getId())) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getLogin();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
// getters en setters
...
}
- regels 35-37: implementeren de methode [getPassword] van de interface [UserDetails]. Het wachtwoord van de gebruiker uit regel 12 wordt teruggegeven;
- regels 39-42: implementeren de methode [getUserName] van de interface [UserDetails]. De gebruikersnaam van regel 12 wordt geretourneerd;
- regels 44-47: het account van de gebruiker verloopt nooit;
- regels 49-52: het account van de gebruiker wordt nooit geblokkeerd;
- regels 54-57: de inloggegevens van de gebruiker verlopen nooit;
- regels 59-62: het account van de gebruiker is altijd actief;
Spring Security vereist ook dat er een klasse bestaat die de interface [AppUserDetailsService] implementeert:
![]() |
Deze interface wordt geïmplementeerd door de volgende klasse [AppUserDetailsService]:
package spring.security.dao;
import generic.jdbc.config.ConfigJdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
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 spring.jdbc.entities.User;
import spring.jdbc.infrastructure.DaoException;
@Service
public class AppUserDetailsService implements UserDetailsService {
// injecties
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
// lokaal
private String simpleClassName = getClass().getSimpleName();
@Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
List<User> users;
try {
// de gebruiker zoeken op basis van zijn login
users = namedParameterJdbcTemplate.query(ConfigJdbc.SELECT_USER_BYLOGIN,
Collections.singletonMap("login", login), new ShortUserMapper());
} catch (Exception e) {
throw new DaoException(145, e, simpleClassName);
}
// gevonden?
if (users.size() == 0) {
throw new UsernameNotFoundException(String.format("login [%s] inexistant", login));
}
// de gegevens van de gebruiker weergeven
return new AppUserDetails(users.get(0), namedParameterJdbcTemplate);
}
}
// --------------------- mappers
class ShortUserMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
return new User(rs.getLong("u_ID"), rs.getLong("u_VERSIONING"), rs.getString("u_NAME"), rs.getString("u_LOGIN"),
rs.getString("u_PASSWORD"));
}
}
- regel 21: de klasse wordt een Spring-component;
- regels 25-26: de database wordt benaderd via JDBC met behulp van het object [NamedParameterJdbcTemplate namedParameterJdbcTemplate] dat is gedefinieerd in de beans van het project [spring-jdbc-generic-04];
- regels 31-49: implementatie van de methode [loadUserByUsername] van de interface [UserDetailsService] (regel 22). De parameter is de gebruikersnaam;
- regels 36-37: de gebruiker wordt opgezocht aan de hand van zijn login. De volgorde SQL [ConfigJdbc.SELECT_USER_BYLOGIN] is als volgt:
public static final String SELECT_USER_BYLOGIN = "SELECT u.ID as u_ID, u.VERSIONING as u_VERSIONING, u.NAME as u_NAME,u.LOGIN as u_LOGIN,u.PASSWORD as u_PASSWORD FROM USERS u WHERE u.LOGIN= :login";
Elke regel die door de SELECT wordt geretourneerd, wordt door de klasse [ShortUserMapper] in de regels 52-58 omgezet in een entiteit [User].
- regels 42-44: als deze niet wordt gevonden, wordt er een uitzondering gegenereerd;
- regel 46: er wordt een object van het type [AppUserDetails] aangemaakt en weergegeven. Dit object is inderdaad van het type [UserDetails] (regel 32). Er worden twee gegevens doorgegeven aan de constructor:
- de gebruiker die is gevonden;
- het object [namedParameterJdbcTemplate] waarmee de klasse [AppUserDetails] de database kan opvragen;
20.2.3. De laag [web]
![]() |
Het project [spring-security-server-jdbc-generic] is afhankelijk van het project [spring-webjson-server-jdbc-generic]:
![]() |
Dit project implementeert de laag [web]. Deze hoeft niet te worden gewijzigd.
20.2.4. De beveiligingsconfiguratie van het project
![]() |
Het project wordt geconfigureerd door de volgende klasse [AppConfig]:
1 ![]() |
We zijn al eerder een configuratieklasse van Spring Security tegengekomen (zie paragraaf 19.2.4):
package hello;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home").permitAll().anyRequest().authenticated();
http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
}
We volgen dezelfde aanpak:
- regel 11: een klasse definiëren die de klasse [WebSecurityConfigurerAdapter] uitbreidt;
- regel 13: een methode [configure(HttpSecurity http)] definiëren die de toegangsrechten tot de verschillende URL van de webservice vastlegt;
- regel 19: een methode [configure(AuthenticationManagerBuilder auth)] definiëren die de gebruikers en hun rollen vastlegt;
De klasse [AppConfig] ziet er als volgt uit:
package spring.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
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 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import spring.security.dao.AppUserDetailsService;
import spring.webjson.server.config.WebConfig;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "spring.security.dao", "spring.security.service" })
@Import({ spring.webjson.server.config.AppConfig.class, WebConfig.class })
public class AppConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AppUserDetailsService appUserDetailsService;
// beveiliging
private boolean activateSecurity = true;
@Override
protected void configure(AuthenticationManagerBuilder registry) throws Exception {
// de authenticatie wordt uitgevoerd door de bean [appUserDetailsService]
// het wachtwoord wordt versleuteld met het hash-algoritme BCrypt
registry.userDetailsService(appUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// CSRF
http.csrf().disable();
// beveiligde applicatie?
if (activateSecurity) {
// het wachtwoord wordt verzonden via de header Authorization: Basic xxxx
http.httpBasic();
// de methode HTTP OPTIONS moet voor iedereen worden toegestaan
http.authorizeRequests() //
.antMatchers(HttpMethod.OPTIONS, "/", "/**").permitAll();
// alleen de rol ADMIN mag de applicatie gebruiken
http.authorizeRequests() //
.antMatchers("/", "/**") // alle URL
.hasRole("ADMIN");
// sessie of niet?
//http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
}
- regel 17: de klasse is een Spring-configuratieklasse;
- regel 18: activeert de Spring Security-elementen;
- regel 26: we halen de Spring-componenten op uit de laag [DAO2] en die uit het pakket [spring.security.service], waarover we later zullen spreken;
- regel 23: we importeren de beans van het project [spring-webjson-server-jdbc-generic], dat de laag [web] implementeert. Onder deze beans bevinden zich ook die van de laag [DAO1];
- regels 22-23: de klasse [AppUserDetails], die gebruikers toegang geeft tot de applicatie, wordt geïnjecteerd;
- regel 26: een booleaanse waarde die de webapplicatie al dan niet (true/false) beveiligt;
- regels 28-33: de methode [configure(HttpSecurity http)] definieert de gebruikers en hun rollen. Deze methode ontvangt als parameter een type [AuthenticationManagerBuilder]. Deze parameter wordt aangevuld met twee gegevens (regel 32):
- een verwijzing naar de service [appUserDetailsService] uit regel 23, die toegang verleent aan geregistreerde gebruikers. Hierbij moet worden opgemerkt dat het feit dat ze in een database zijn opgeslagen, niet wordt vermeld. Ze zouden dus in een cache kunnen staan, door een webservice kunnen worden geleverd, ...
- het type versleuteling dat voor het wachtwoord wordt gebruikt. We hebben het algoritme BCrypt gebruikt;
- regels 35-53: de methode [configure(HttpSecurity http)] definieert de toegangsrechten voor de URL van de webservice;
- regel 38: we hebben in het inleidende project gezien dat Spring Security standaard een CSRF-token (Cross Site Request Forgery) beheert dat de gebruiker die zich wilde authenticeren, naar de server moest terugsturen. Hier is dit mechanisme uitgeschakeld. In combinatie met de booleaanse waarde (isSecured=false) maakt dit het mogelijk om de webapplicatie zonder beveiliging te gebruiken;
- regel 42: we schakelen de authenticatiemodus via de header HTTP in. De client moet de volgende header HTTP verzenden:
waarbij code de Base64-codering is van de tekenreeks **login:password**. De Base64-codering van de tekenreeks *admin:admin is bijvoorbeeld YWRtaW46YWRtaW4=*. De gebruiker met de login [admin] en het wachtwoord [admin] zal dus de volgende header HTTP verzenden om zich te authenticeren:
- regels 47-49: geven aan dat alle URL van de webservice toegankelijk zijn voor gebruikers met de rol [ROLE_ADMIN]. Dit betekent dat een gebruiker die deze rol niet heeft, geen toegang heeft tot de webservice;
- regel 51: in de modus [session] hoeft een gebruiker die zich eenmaal heeft geauthenticeerd, dit bij volgende toegangen niet meer te doen. Dit is de standaardinstelling van Spring Security. Regel 51 schakelt deze modus uit. Als deze actief is, moet de gebruiker zich bij elke toegang authenticeren. Zonder sessie is de responsiviteit van de beveiligde webservice lager dan met een sessie, daarom is regel 51 uitgecommentarieerd;
20.2.5. Testen van de beveiligde webservice
We gaan de webservice testen met de Chrome-client [Advanced Rest Client]. We moeten de authenticatie-header HTTP specificeren:
waarbij [code] de Base64-code is van de tekenreeks [login:password]. Om deze code te genereren, kunnen we het volgende programma uit het project [spring-security-create-users] gebruiken:
![]() |
package spring.security.helpers;
import org.springframework.security.crypto.codec.Base64;
public class Base64Encoder {
public static void main(String[] args) {
// er worden twee argumenten verwacht: login en wachtwoord
if (args.length != 2) {
System.out.println("Syntaxe : login password");
System.exit(0);
}
// de twee argumenten worden opgehaald
String chaîne = String.format("%s:%s", args[0], args[1]);
// de tekenreeks wordt gecodeerd
byte[] data = Base64.encode(chaîne.getBytes());
// de Base64-codering wordt weergegeven
System.out.println(new String(data));
}
}
Als we dit programma uitvoeren met de twee argumenten [admin admin]:
![]() |
krijgen we het volgende resultaat:
We zijn nu klaar om te testen:
- SGBD en MySQL moeten worden gestart;
- we vullen de tabellen [PRODUITS] en [CATEGORIES] met de uitvoeringsconfiguratie met de naam [spring-jdbc-generic-04-fillDataBase]:
![]() |
- als dit nog niet is gebeurd, vullen we de tabellen [USERS, ROLES, USERS_ROLES] met de uitvoeringsconfiguratie met de naam [spring-security-create-users-hibernate-eclipselink]:
![]() |
- we starten de beveiligde webservice met de uitvoeringsconfiguratie met de naam [spring-security-server-jdbc-generic]:
![]() |
Vervolgens vragen we met de Chrome-client [Advanced Rest Client] de uitgebreide versie van alle categorieën op:
![]() |
- in [1] vragen we de URL van de uitgebreide categorieën op;
- in [2], met een methode GET;
- in [3] geven we de header HTTP voor de authenticatie. De code [YWRtaW46YWRtaW4=] is de Base64-codering van de tekenreeks [admin:admin];
- in [4] verzenden we het commando HTTP;
Het antwoord van de server is als volgt:
![]() |
- in [1], de authenticatieheader HTTP;
- in [2] stuurt de server een antwoord terug: jSON;
We krijgen inderdaad de lijst met categorieën:
![]() |
Laten we nu een verzoek HTTP proberen met een onjuiste authenticatieheader. Het antwoord is dan als volgt:
![]() |
- in [1]: de authenticatieheader HTTP;
We krijgen het volgende antwoord:
![]() |
- in [2]: het antwoord van de webservice;
Laten we nu de gebruiker user / user proberen. Deze bestaat wel, maar heeft geen toegang tot de webservice. Als we het Base64-encoderingsprogramma uitvoeren met de twee argumenten [user user]:
![]() |
krijgen we het volgende resultaat:
![]() |
- in [1]: de onjuiste authenticatieheader HTTP;
![]() |
- in [2]: het antwoord van de webservice. Dit verschilt van het vorige, dat [401 Unauthorized] was. Deze keer heeft de gebruiker zich correct geauthenticeerd, maar beschikt hij niet over voldoende rechten om toegang te krijgen tot URL;
Een beveiligde webservice is nu operationeel.
20.2.6. Een authenticatie-URL
![]() |
We gaan een URL maken waarmee we kunnen vaststellen of een gebruiker al dan niet bevoegd is om toegang te krijgen tot de webservice. Hiervoor maken we de volgende nieuwe controller MVC [AuthenticateController]:
package spring.security.service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import spring.webjson.server.service.Response;
@RestController
public class AuthenticateController {
@RequestMapping(value = "/authenticate", method = RequestMethod.GET)
public Response<Void> authenticate() {
return new Response<Void>(0, null, null);
}
}
- regel 9: de klasse [AuthenticateController] is een Spring-controller. Als zodanig stelt deze URL beschikbaar. De annotatie [@RestController] geeft aan dat de methoden die deze URL verwerken, zelf hun antwoord aan de client retourneren;
- regel 11: geeft de URL [/authenticate] weer;
- regels 12-14: de methode geeft gewoon een leeg [Response]-object terug, maar met een [status] gelijk aan 0, wat aangeeft dat er geen fout is opgetreden;
Waarvoor dient deze URL? Wanneer we een gebruiker willen authenticeren, zullen we hierom vragen. We hebben gezien dat als de beveiligingslaag deze gebruiker niet accepteert, er een uitzondering wordt teruggegeven. Hier is een voorbeeld;
Met de gebruiker [admin:admin]:
![]() | ![]() |
We krijgen een leeg antwoord, maar geen uitzondering.
Met de gebruiker [user:user]:
![]() | ![]() |
Er is een uitzondering opgetreden.
20.2.7. Conclusie
De toevoeging van de benodigde klassen aan Spring Security kon plaatsvinden zonder wijzigingen aan het oorspronkelijke web-/json-project. Dit zeer gunstige scenario vloeit voort uit het feit dat de drie tabellen die aan de database zijn toegevoegd, onafhankelijk zijn van de bestaande tabellen. We hadden ze zelfs in een aparte database kunnen plaatsen. In andere gevallen kunnen de toegevoegde tabellen relaties hebben met de bestaande tabellen. De code van de bestaande [DAO]-laag moet dan worden herzien.
20.3. Een client geprogrammeerd voor de beveiligde webservice / jSON
We hebben al een client geschreven voor de onbeveiligde webservice / jSON:
![]() |
We gaan nu een client maken die is geprogrammeerd voor de beveiligde webservice:
![]() |
![]() |
20.3.1. De laag [Client HTTP]
![]() |
![]() | ![]() |
De klasse [Client] zorgt voor de communicatie HTTP met de beveiligde webserver / jSON. Zoals we zojuist hebben gezien, moet de client bij deze communicatie HTTP voortaan een authenticatieheader verzenden, bijvoorbeeld:
De interface [IClient] ziet er dan als volgt uit:
package spring.webjson.client.dao;
import org.springframework.http.HttpMethod;
import spring.webjson.client.entities.Credentials;
public interface IClient {
public <T1, T2> T1 getResponse(Credentials credentials,String url, HttpMethod method, int errStatus, T2 body);
}
- regel 8: de eerste parameter van de methode [getResponse] is nu een object [Credentials] dat de identificatiegegevens van een gebruiker bevat:
package spring.security.client.entities;
public class Credentials {
// eigenschappen
private String login;
private String password;
// constructor
public Credentials() {
}
public Credentials(String login, String password) {
this.login = login;
this.password = password;
}
// getters en setters
...
}
De klasse [Client], die de interface [IClient] implementeert, verandert als volgt:
package spring.security.client.dao;
...
@Component
public class Client implements IClient {
// injecties
@Autowired
protected RestTemplate restTemplate;
@Autowired
protected String urlServiceWebJson;
// lokaal
private String simpleClassName = getClass().getSimpleName();
private String getBase64(Credentials credentials) {
// de gebruiker en het wachtwoord worden in base64 gecodeerd – vereist Java 8
String chaîne = String.format("%s:%s", credentials.getLogin(), credentials.getPassword());
return String.format("Basic %s", new String(Base64.getEncoder().encode(chaîne.getBytes())));
}
// algemene aanvraag
@Override
public <T1, T2> T1 getResponse(Credentials credentials, String url, HttpMethod method, int errStatus, T2 body) {
// het antwoord van de server
ResponseEntity<Response<T1>> response;
try {
// het verzoek wordt voorbereid
RequestEntity<?> request = null;
if (method == HttpMethod.GET) {
HeadersBuilder<?> headersBuilder = RequestEntity.get(new URI(String.format("%s%s", urlServiceWebJson, url))) .accept(MediaType.APPLICATION_JSON);
if (credentials != null) {
headersBuilder = headersBuilder.header("Authorization", getBase64(credentials));
}
request = headersBuilder.build();
}
if (method == HttpMethod.POST) {
BodyBuilder bodyBuilder = RequestEntity.post(new URI(String.format("%s%s", urlServiceWebJson, url))).header("Content-Type", "application/json").accept(MediaType.APPLICATION_JSON);
if (credentials != null) {
bodyBuilder = bodyBuilder.header("Authorization", getBase64(credentials));
}
request = bodyBuilder.body(body);
}
// het verzoek wordt uitgevoerd
response = restTemplate.exchange(request, new ParameterizedTypeReference<Response<T1>>() {
});
} catch (Exception e) {
// de uitzondering wordt ingekapseld
throw new DaoException(errStatus, e, simpleClassName);
}
...
}
...
}
- regels 33-35, 40-42: als de gebruiker [credentials] niet null is, wordt de authenticatieheader toegevoegd. De codering Base64 van de gebruiker en zijn wachtwoord wordt verzorgd door de methode [getBase64] in de regels 17-21. Let erop dat deze methode gebruikmaakt van een klasse [Base64] die behoort tot JDK 1.8. Onze client HTTP kan werken met een onbeveiligde webservice. Het volstaat om hem een [credentials] door te geven die gelijk is aan null;
- afgezien van de voorgaande regels blijft de code ongewijzigd;
20.3.2. De laag [DAO]
![]() |
20.3.2.1. De interface [IDao]
![]() |
Alle methoden van de interface [IDao] van het project [spring-webjson-client-generic] krijgen een extra parameter [Credentials credentials]:
package spring.security.client.dao;
import java.util.List;
import spring.security.client.entities.AbstractCoreEntity;
import spring.security.client.entities.Credentials;
public interface IDao<T extends AbstractCoreEntity> extends IAuthenticate {
// lijst van alle T-entiteiten
public List<T> getAllShortEntities(Credentials credentials);
public List<T> getAllLongEntities(Credentials credentials);
// van specifieke entiteiten – korte versie
public List<T> getShortEntitiesById(Credentials credentials, Iterable<Long> ids);
public List<T> getShortEntitiesById(Credentials credentials, Long... ids);
public List<T> getShortEntitiesByName(Credentials credentials, Iterable<String> names);
public List<T> getShortEntitiesByName(Credentials credentials, String... names);
// van specifieke entiteiten – lange versie
public List<T> getLongEntitiesById(Credentials credentials, Iterable<Long> ids);
public List<T> getLongEntitiesById(Credentials credentials, Long... ids);
public List<T> getLongEntitiesByName(Credentials credentials, Iterable<String> names);
public List<T> getLongEntitiesByName(Credentials credentials, String... names);
// meerdere entiteiten bijwerken
public List<T> saveEntities(Credentials credentials, Iterable<T> entities);
public List<T> saveEntities(Credentials credentials, @SuppressWarnings("unchecked") T... entities);
// verwijdering van alle entiteiten
public void deleteAllEntities(Credentials credentials);
// verwijdering van meerdere entiteiten
public void deleteEntitiesById(Credentials credentials, Iterable<Long> ids);
public void deleteEntitiesById(Credentials credentials, Long... ids);
public void deleteEntitiesByName(Credentials credentials, Iterable<String> names);
public void deleteEntitiesByName(Credentials credentials, String... names);
public void deleteEntitiesByEntity(Credentials credentials, Iterable<T> entities);
public void deleteEntitiesByEntity(Credentials credentials, @SuppressWarnings("unchecked") T... entities);
}
- regel 8: de interface [IDao] breidt de volgende interface [IAuthenticate] uit:
package spring.security.client.dao;
import spring.security.client.entities.Credentials;
public interface IAuthenticate {
// authenticatie
public void authenticate(Credentials credentials);
}
De interface [IAuthenticate] heeft slechts één methode: [authenticate]. Deze methode retourneert niets (void) als de gebruiker [Credentials credentials] door de beveiligde webservice wordt geaccepteerd; anders wordt er een uitzondering gegenereerd.
20.3.2.2. De klasse [AbstractDao]
![]() |
Ter herinnering: de klasse [AbstractDao] is de bovenliggende klasse van de klassen [DaoCategorie], die de URL van de categorieën beheren, en [DaoProduit], die de URL van de producten. Alle methoden van de klasse [AbstractDao] van het project [spring-webjson-client-generic] ontvangen een extra parameter [Credentials credentials] die ze doorgeven aan de onderliggende klasse. Hier volgt een voorbeeld:
@Override
public List<T1> getShortEntitiesById(Credentials credentials, Iterable<Long> ids) {
// geldigheid van het argument
List<T1> entities = checkNullOrEmptyArgument(true, ids);
if (entities != null) {
return entities;
}
// resultaat
return getShortEntitiesById(credentials, Lists.newArrayList(ids));
}
- de methode [getShortEntitiesById] ontvangt de parameter [Credentials credentials] (regel 2) en geeft deze door (regel 9) aan de methode [getShortEntitiesById] van de dochterklasse;
De klasse [AbstractDao] heeft de volgende structuur:
package spring.security.client.dao;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import spring.security.client.entities.AbstractCoreEntity;
import spring.security.client.entities.Credentials;
import spring.security.client.infrastructure.MyIllegalArgumentException;
import com.google.common.collect.Lists;
public abstract class AbstractDao<T1 extends AbstractCoreEntity> implements IDao<T1> {
@Autowired
private IAuthenticate authenticate;
...
}
- regel 14: de klasse implementeert de interface [IDao] die we hebben beschreven;
- regels 16-17: er wordt een instantie van de interface [IAuthenticate] geïnjecteerd. Deze wordt geïmplementeerd door de volgende klasse [Authenticate]:
package spring.security.client.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import spring.security.client.entities.Credentials;
@Component
public class Authenticate implements IAuthenticate{
@Autowired
protected IClient client;
// controle [credentials,mdp]
public void authenticate(Credentials credentials) {
client.<Void, Void> getResponse(credentials, "/authenticate", HttpMethod.GET, 111, (Void) null);
}
}
- regel 9: de klasse [Authenticate] is een Spring-component;
- regel 10: die de interface [IAuthenticate] implementeert;
- regels 11-12: injectie van de client HTTP waarmee communicatie met de beveiligde webservice mogelijk is;
- regels 15-17: implementatie van de methode [authenticate] van de interface;
- regel 16: er wordt een commando HTTP GET verzonden naar de URL [/authenticate]. Het gebruik van deze URL is in paragraaf 20.2.6 uitgelegd. Het principe is dat de aanroep met een uitzondering eindigt als de gebruiker [credentials] onbekend is of onvoldoende rechten heeft;
De klasse [AbstractDao] implementeert de methode [authenticate] van de interface [IDao] als volgt:
@Autowired
private IAuthenticate authenticate;
@Override
public void authenticate(Credentials credentials) {
authenticate.authenticate(credentials);
}
- regel 7: de taak wordt gedelegeerd aan de methode [authenticate] van de klasse [Authenticate]. Er treedt dus een uitzondering op als de gebruiker [Credentials credentials] niet wordt geaccepteerd door de beveiligde webservice;
20.3.2.3. De klassen [DaoCategorie, DaoProduit]
![]() |
De klassen [DaoCategorie, DaoProduit] zijn die van het project [spring-webjson-server-generic] met de extra parameter [Credentials credentials]. Hier volgt een voorbeeld:
@Component
public class DaoCategorie extends AbstractDao<Categorie> {
// injecties
@Autowired
protected ApplicationContext context;
@Autowired
protected IClient client;
@Override
public List<Categorie> getAllShortEntities(Credentials credentials) {
try {
// filters jSON
ObjectMapper mapper = context.getBean("jsonMapperShortCategorie", ObjectMapper.class);
// alle categorieën ophalen
Object map = client.<List<Categorie>, Void> getResponse(credentials, "/getAllShortCategories", HttpMethod.GET,
202, null);
// de lijst met categorieën List<Categorie>
return mapper.readValue(mapper.writeValueAsString(map), new TypeReference<List<Categorie>>() {
});
} catch (DaoException e1) {
throw e1;
} catch (Exception e2) {
throw new DaoException(221, e2, simpleClassName);
}
}
....
20.3.3. De Spring-configuratie
![]() |
De klasse [AppConfig] configureert de Spring-omgeving van het project. Deze is identiek aan die in het project [spring-webjson-client-generic], op één detail na:
@Configuration
@ComponentScan({ "spring.security.client.dao" })
public class AppConfig {
- regel 2: hier moet het pakket van de nieuwe laag [DAO] worden ingevuld;
20.3.4. Tests van de laag [DAO]
![]() |
![]() |
20.3.4.1. De test [JUnitTestCredentials]
De test [JUnitTestCredentials] maakt gebruik van de methode [IDao.authenticate] om te controleren of bepaalde gebruikers geldig zijn of niet:
package client.tests.junit;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import spring.security.client.config.AppConfig;
import spring.security.client.dao.IAuthenticate;
import spring.security.client.entities.Credentials;
import spring.security.client.infrastructure.DaoException;
@SpringApplicationConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class JUnitTestCredentials {
// laag [DAO]
@Autowired
private IAuthenticate authenticate;
// gebruikers
static private Credentials admin;
static private Credentials user;
static private Credentials unknown;
@BeforeClass
public static void init() {
admin = new Credentials("admin", "admin");
user = new Credentials("user", "user");
unknown = new Credentials("x", "y");
}
@Test()
public void checkUserUser() {
DaoException se = null;
try {
authenticate.authenticate(user);
} catch (DaoException e) {
se = e;
System.out.println("checkUserUser: " + e);
}
Assert.assertNotNull(se);
Assert.assertEquals("403 Forbidden", se.getExceptions().get(0).getErrorMessage());
}
@Test()
public void checkUserUnknown() {
DaoException se = null;
try {
authenticate.authenticate(unknown);
} catch (DaoException e) {
se = e;
System.out.println("checkUserUnknown : " + e);
}
Assert.assertNotNull(se);
Assert.assertEquals("401 Unauthorized", se.getExceptions().get(0).getErrorMessage());
}
@Test()
public void checkUserAdmin() {
DaoException se = null;
try {
authenticate.authenticate(admin);
} catch (DaoException e) {
se = e;
System.out.println("checkUserAdmin : " + e);
}
Assert.assertNull(se);
}
}
- tijdens het initialiseren van de testklasse, regels 29-34, worden drie gebruikers aangemaakt:
- de gebruiker [admin] heeft toegang tot de URL van de webservice. Dit wordt getest in de regels 63-72;
- de gebruiker [user] bestaat, maar heeft geen toestemming om de URL van de webservice te gebruiken. Deze wordt getest in de regels 37-47;
- de gebruiker [unknown] bestaat niet. Dit wordt getest in de regels 50-60;
De beveiligde webservice wordt gestart met de uitvoeringsconfiguratie met de naam [spring-security-server-jdbc-generic] [1]:
![]() |
Vervolgens wordt de test JUnit [JUnitTestCredentials] gestart met de uitvoeringsconfiguratie [spring-security-client-generic-JUnitTestCredentials] [2]. De verkregen console-resultaten zijn als volgt:
en de test is geslaagd:
![]() |
20.3.4.2. De test [JUnitTestDao]
De test [JUnitTestDao] is identiek aan wat hij was in het onbeveiligde project [spring-webjson-client-generic], behalvebehalve dat nu de geteste methoden van de laag [DAO] allemaal de gebruiker [admin / admin] als eerste parameter hebben:
@SpringApplicationConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class JUnitTestDao {
// Spring-context
@Autowired
private ApplicationContext context;
// laag [DAO]
@Autowired
private IDao<Produit> daoProduit;
@Autowired
private IDao<Categorie> daoCategorie;
....
// gebruikers
static private Credentials admin;
@BeforeClass
public static void init() {
admin = new Credentials("admin", "admin");
}
@Before
public void clean() {
// de database wordt vóór elke test opgeschoond
log("Vidage de la base de données", 1);
// de tabel [CATEGORIES] wordt leeggemaakt en vervolgens de tabel [PRODUITS]
daoCategorie.deleteAllEntities(admin);
// de woordenboeken worden leeggemaakt
for (Long id : mapCategories.keySet()) {
mapCategories.remove(id);
}
for (Long id : mapProduits.keySet()) {
mapProduits.remove(id);
}
}
private List<Categorie> fill(int nbCategories, int nbProduits) {
// de tabellen worden gevuld
...
// de categorie wordt toegevoegd – de producten worden vervolgens ook
// ingevoegd – het resultaat wordt tegelijkertijd weergegeven
return daoCategorie.saveEntities(admin, categories);
}
private Object[] showDataBase() throws BeansException, JsonProcessingException {
// lijst met categorieën
log("Liste des catégories", 2);
List<Categorie> categories = daoCategorie.getAllShortEntities(admin);
affiche(categories, context.getBean("jsonMapperShortCategorie", ObjectMapper.class));
// lijst met producten
log("Liste des produits", 2);
List<Produit> produits = daoProduit.getAllShortEntities(admin);
affiche(produits, context.getBean("jsonMapperShortProduit", ObjectMapper.class));
// resultaat
return new Object[] { categories, produits };
}
...
Alle bewerkingen worden uitgevoerd met de gebruiker [admin / admin], die als enige toegang heeft tot de beveiligde webservice.
We starten de test met de uitvoeringsconfiguratie met de naam [spring-security-client-generic-JUnitTestDao]:
![]() |
De test slaagt, maar we zien dat deze trager verloopt dan bij de onbeveiligde webservice. Het beveiligen van een applicatie verlengt de responstijden aanzienlijk. Er is een belangrijke factor die de prestaties van de beveiligde webservice beïnvloedt: in de klasse [AppConfig], die deze configureert, hebben we het volgende geschreven:
@Override
protected void configure(HttpSecurity http) throws Exception {
// CSRF
http.csrf().disable();
// beveiligde applicatie?
if (activateSecurity) {
// het wachtwoord wordt verzonden via de header Authorization: Basic xxxx
http.httpBasic();
// de methode HTTP OPTIONS moet voor iedereen zijn toegestaan
http.authorizeRequests() //
.antMatchers(HttpMethod.OPTIONS, "/", "/**").permitAll();
// alleen de rol ADMIN mag de applicatie gebruiken
http.authorizeRequests() //
.antMatchers("/", "/**") // alle URL
.hasRole("ADMIN");
// geen sessie
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
Regel 17 heeft gevolgen. Deze regel bepaalt of de gebruiker zich bij elke toegang moet authenticeren of niet. Als we deze regel uitcommentariëren, duurt de test JUnit aanzienlijk korter, omdat de gebruiker [admin] zich alleen bij de eerste test authentificeert en niet bij de volgende (ook al wordt de authenticatieheader HTTP door de client verzonden, controleert de server het wachtwoord van de gebruiker niet opnieuw).
20.4. Het Eclipse-project [spring-security-server-jpa-generic]
De beveiligde webservice wordt nu geïmplementeerd door het project [spring-security-server-jpa-generic], dat voortbouwt op het project [spring-jpa-generic], dat de toegang tot de database beheert met Spring Data JPA:
![]() |
Hierboven:
- de laag [DAO1] is de laag [DAO], die de tabellen [PRODUITS] en [CATEGORIES] van de database [dbproduitscategories] beheert. Deze is al geschreven;
- de laag [DAO2] is de laag [DAO] die de tabellen [USERS], [ROLES] en [USERS_ROLES] van de database [dbproduitscategories]. Deze moet nog worden geschreven;
Het project [spring-security-server-jpa-generic] wordt in eerste instantie verkregen door het eerder bestudeerde project [spring-security-server-jdbc-generic] te kopiëren. De lagen [web] en [security] veranderen namelijk niet, omdat:
- de laag [DAO1 / Repositories / JPA] (reeds geschreven) dezelfde interface heeft als de laag [DAO1 / JDBC];
- de laag [DAO2 / Repositories / JPA] (nog te schrijven) dezelfde interface zal hebben als de laag [DAO2 / JDBC];
Het project [spring-security-server-jpa-generic] is als volgt:
![]() |
- het pakket [spring.security.repositories] implementeert de laag [repositories];
- het pakket [spring.security.dao] implementeert de laag [dao2];
20.4.1. Het Maven-project
Het project is een Maven-project dat is geconfigureerd door het volgende bestand [pom.xml]:
<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>dvp.spring.database</groupId>
<artifactId>spring-security-server-jpa-generic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-server-jpa-generic</name>
<description>démo spring security</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- webserver / jSON -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>spring-webjson-server-jpa-generic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<!-- plug-ins -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- regels 24-27: de afhankelijkheid voor de laag [security] van het project;
- regels 29-33: de afhankelijkheid voor de laag [web] van het project. Het project [spring-webjson-server-jpa-generic] implementeert de laag [web] volledig. Deze hoeft niet te worden geschreven of gewijzigd;
Uiteindelijk zijn de afhankelijkheden als volgt:
![]() |
20.4.2. De Spring-configuratie
![]() |
Het configuratiebestand [AppConfig] van het vorige project [spring-security-server-jdbc-generic] is geschikt. Er hoeft alleen een extra configuratie aan te worden toegevoegd:
@Configuration
@EnableWebSecurity
@EnableJpaRepositories(basePackages = { "spring.security.repositories" })
@ComponentScan(basePackages = { "spring.security.dao", "spring.security.service" })
@Import({ spring.webjson.server.config.AppConfig.class })
public class AppConfig extends WebSecurityConfigurerAdapter {
- regel 3: we definiëren het pakket dat de laag implementeert [repositories];
- regel 4: de pakketten die de Spring-beans bevatten, hebben in het nieuwe project dezelfde naam;
- regel 5: in het vorige project was de klasse [spring.webjson.server.config.AppConfig] te vinden in de afhankelijkheid [spring-webjson-server-jdbc-generic]. Hier is deze te vinden in de afhankelijkheid [spring-webjson-server-jpa-generic];
20.4.3. De laag JPA
![]() |
De entiteiten JPA die worden beheerd door de laag [JPA], zijn te vinden in het project [mysql-config-jpa-hibernate] [2], dat een afhankelijkheid is van het project [1]:
![]() |
De klasse [User] is de afbeelding van de tabel [USERS]:

- ID: primaire sleutel;
- VERSION: versiekolom van de rij;
- IDENTITY: een beschrijvende identiteit van de gebruiker;
- LOGIN: de gebruikersnaam van de gebruiker;
- PASSWORD: zijn wachtwoord;
package generic.jpa.entities.dbproduitscategories;
import generic.jdbc.config.ConfigJdbc;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
@Table(name = ConfigJdbc.TAB_USERS)
public class User implements AbstractCoreEntity {
// eigenschappen
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = ConfigJdbc.TAB_JPA_ID)
protected Long id;
@Version
@Column(name = ConfigJdbc.TAB_JPA_VERSIONING)
protected Long version;
@Transient
protected EntityType entityType=EntityType.POJO;
// eigenschappen
@Column(name = ConfigJdbc.TAB_USERS_NAME, length = 30, nullable = false)
private String name;
@Column(name = ConfigJdbc.TAB_USERS_LOGIN, length = 30, unique = true, nullable = false)
private String login;
@Column(name = ConfigJdbc.TAB_USERS_PASSWORD, length = 60, nullable = false)
private String password;
// de bijbehorende UserRole
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = { CascadeType.ALL })
@JsonIgnore
private List<UserRole> userRoles;
// makers
public User() {
}
public User(Long id, Long version, String identity, String login, String password) {
this.id = id;
this.version = version;
this.name = identity;
this.login = login;
this.password = password;
}
// ------------------------------------------------------------
// herdefinitie van [equals] en [hashcode]
...
// getters en setters
...
}
- regel 23: de klasse implementeert de interface [AbstractCoreEntity] die al voor de andere entiteiten wordt gebruikt;
- regels 34-35: het type van de entiteit. Deze eigenschap wordt niet opgeslagen in de database [@Transient];
- regels 38-43: de drie basiskenmerken van een gebruiker (name, login, password);
- regels 46-48: de lijst met rollen van de gebruiker. Hij kan er meerdere hebben. We zullen ook zien dat aan één rol meerdere gebruikers kunnen worden gekoppeld. We hebben dus, in de zin van de term, een relatie tussen de entiteiten [User] en [Role]:
- een gebruiker kan aan meerdere rollen worden gekoppeld;
- een rol kan naar meerdere gebruikers verwijzen;
Deze relatie [ManyToMany] wordt in de database geïmplementeerd door de koppelingstabel [USERS_ROLES]. Als een gebruiker U een relatie heeft met een rol R, wordt deze relatie in de tabel [USERS_ROLES] vastgelegd door het primaire sleutelpaar van de entiteiten (U,R) te registreren. In de tabel JPA kan de relatie [ManyToMany], die de entiteiten [User] en [Role] met elkaar verbindt, worden opgesplitst in twee relaties [ManyToOne, OneToMany]:
- (vervolg)
- een relatie [ManyToOne] van de entiteit [User] naar de entiteit [UserRole];
- een relatie [OneToMany] van de entiteit [UserRole] naar de entiteit [UserRole];
Evenzo kan de relatie [ManyToMany], die de entiteiten [Role] en [User] met elkaar verbindt, worden opgesplitst in twee relaties [ManyToOne, OneToMany]:
- (vervolg)
- een relatie [ManyToOne] van de entiteit [Role] naar de entiteit [UserRole];
- een relatie [OneToMany] van de entiteit [UserRole] naar de entiteit [User];
- relatie 48: het feit dat een gebruiker meerdere rollen heeft, wordt weergegeven door een relatie [OneToMany] naar de entiteit [UserRole];
De klasse [Role] is de weergave van de tabel [ROLES]:

- ID: primaire sleutel;
- VERSION: versiekolom van de rij;
- NAME: rolnaam. Standaard verwacht Spring Security namen in de vorm ROLE_XX, bijvoorbeeld ROLE_ADMIN of ROLE_GUEST;
package generic.jpa.entities.dbproduitscategories;
import generic.jdbc.config.ConfigJdbc;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
@Table(name = ConfigJdbc.TAB_ROLES)
public class Role implements AbstractCoreEntity {
// eigenschappen
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = ConfigJdbc.TAB_JPA_ID)
protected Long id;
@Version
@Column(name = ConfigJdbc.TAB_JPA_VERSIONING)
protected Long version;
@Transient
protected EntityType entityType=EntityType.POJO;
// eigenschappen
@Column(name = ConfigJdbc.TAB_ROLES_NAME, length = 30, unique = true, nullable = false)
private String name;
// de bijbehorende UserRole
@OneToMany(fetch = FetchType.LAZY, mappedBy = "role", cascade = { CascadeType.ALL })
@JsonIgnore
private List<UserRole> userRoles;
// constructors
public Role() {
}
public Role(Long id, Long version, String name) {
this.id = id;
this.version = version;
this.name = name;
}
// getters en setters
public Role(String name) {
this.name = name;
}
// ------------------------------------------------------------
// herdefinitie van [equals] en [hashcode]
...
// getters en setters
...
}
- regels 42-44: het feit dat aan een rol meerdere gebruikers kunnen worden gekoppeld, wordt weergegeven door een relatie [@OneToMany] naar de entiteit [UserRole];
De klasse [UserRole] is de weergave van de tabel [USERS_ROLES]:

Een gebruiker kan meerdere rollen hebben, en een rol kan meerdere gebruikers omvatten. Er is sprake van een veel-op-veel-relatie, die wordt weergegeven door de tabel [USERS_ROLES].
- ID: primaire sleutel;
- VERSION: versiekolom van de rij;
- USER_ID: gebruikers-ID;
- ROLE_ID: rol-ID;
package generic.jpa.entities.dbproduitscategories;
import generic.jdbc.config.ConfigJdbc;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
@Entity
@Table(name = ConfigJdbc.TAB_USERS_ROLES)
public class UserRole implements AbstractCoreEntity {
// eigenschappen
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = ConfigJdbc.TAB_JPA_ID)
protected Long id;
@Version
@Column(name = ConfigJdbc.TAB_JPA_VERSIONING)
protected Long version;
@Transient
protected EntityType entityType=EntityType.POJO;
// een UserRole verwijst naar een User
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = ConfigJdbc.TAB_USERS_ROLES_USER_ID, nullable = false)
private User user;
// een UserRole verwijst naar een rol
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = ConfigJdbc.TAB_USERS_ROLES_ROLE_ID, nullable = false)
private Role role;
// constructors
public UserRole() {
}
public UserRole(User user, Role role) {
this.user = user;
this.role = role;
}
// ------------------------------------------------------------
// herdefinitie van [equals] en [hashcode]
...
// getters en setters
...
}
- regels 34-36: vormen de vreemde sleutel van de tabel [USERS_ROLES] naar de tabel [USERS];
- regels 38-41: geven de vreemde sleutel weer van de tabel [USERS_ROLES] naar de tabel [ROLES];
20.4.4. De laag [repositories]
![]() |
![]() |
De interface [UserRepository] beheert de toegang tot de entiteiten [User]:
package spring.security.repositories;
import generic.jpa.entities.dbproduitscategories.Role;
import generic.jpa.entities.dbproduitscategories.User;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
// lijst met rollen van een gebruiker geïdentificeerd aan de hand van zijn id
@Query("select ur.role from UserRole ur where ur.user.id=?1")
Iterable<Role> getRoles(long id);
// lijst met rollen van een gebruiker geïdentificeerd aan de hand van zijn unieke login
@Query("select ur.role from UserRole ur where ur.user.login=?1 and ur.user.password=?2")
Iterable<Role> getRoles(String login, String password);
// zoeken naar een gebruiker op basis van zijn login
User findUserByLogin(String login);
}
- regel 9: de interface [UserRepository] breidt de interface [CrudRepository] van Spring Data uit (regel 7);
- regels 12-13: met de methode [getRoles(long id)] kunnen alle rollen worden opgehaald van een gebruiker die is geïdentificeerd aan de hand van zijn [id]
- regels 16-17: idem, maar dan voor een gebruiker die wordt geïdentificeerd aan de hand van zijn login en wachtwoord;
- regel 20: om een gebruiker op te zoeken via zijn gebruikersnaam;
De interface [RoleRepository] beheert de toegang tot de entiteiten [Role]:
package spring.security.repositories;
import generic.jpa.entities.dbproduitscategories.Role;
import org.springframework.data.repository.CrudRepository;
public interface RoleRepository extends CrudRepository<Role, Long> {
// zoeken naar een rol op naam
Role findRoleByName(String name);
}
- regel 7: de interface [RoleRepository] breidt de interface [CrudRepository] uit;
- regel 10: men kan een rol opzoeken via de naam ervan. Hierbij wordt erop gewezen dat de entiteit [Role] een veld [name] heeft. De methode [findEntityByChamp] wordt automatisch geïmplementeerd door Spring Data. Het is dus niet nodig om de methode [finRoleByName] hier te implementeren. Deze hoeft alleen in de interface te worden gedeclareerd.
De interface [UserRoleRepository] regelt de toegang tot de entiteiten [UserRole]:
package spring.security.repositories;
import generic.jpa.entities.dbproduitscategories.UserRole;
import org.springframework.data.repository.CrudRepository;
public interface UserRoleRepository extends CrudRepository<UserRole, Long> {
}
- regel 7: de interface [UserRoleRepository] breidt alleen de interface [CrudRepository] uit zonder er nieuwe methoden aan toe te voegen;
20.4.5. De laag [DAO2]
![]() |
![]() |
In de laag [DAO2] vinden we dezelfde klassen terug als in de laag [DAO2] van het project [spring-security-server-jdbc-generic] dat eerder in paragraaf 20.2.2 is besproken. Ze moeten nu alleen nog worden geïmplementeerd met behulp van de klassen uit de laag [repositories].
De klasse [AppUserDetails] verandert als volgt:
package spring.security.dao;
import generic.jpa.entities.dbproduitscategories.Role;
import generic.jpa.entities.dbproduitscategories.User;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import spring.data.infrastructure.DaoException;
import spring.security.repositories.UserRepository;
public class AppUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
// eigenschappen
private User user;
private UserRepository userRepository;
// lokaal
private String simpleClassName = getClass().getSimpleName();
// constructors
public AppUserDetails() {
}
public AppUserDetails(User user, UserRepository userRepository) {
this.user = user;
this.userRepository = userRepository;
}
// -------------------------interface
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
Iterable<Role> roles;
try {
roles = userRepository.getRoles(user.getId());
} catch (Exception e) {
e.printStackTrace();
throw new DaoException(167, e, simpleClassName);
}
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
...
}
- in regel 31 ontvangt de constructor van de klasse als tweede parameter het object [UserRepository], waarmee de klasse de rollen van een bepaalde gebruiker kan ophalen (regel 42);
De Spring-component [AppUserDetailsService] ontwikkelt zich als volgt:
package spring.security.dao;
import generic.jpa.entities.dbproduitscategories.User;
import org.springframework.beans.factory.annotation.Autowired;
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 spring.data.infrastructure.DaoException;
import spring.security.repositories.UserRepository;
@Service
public class AppUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
// lokaal
private String simpleClassName = getClass().getName();
@Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
// de gebruiker wordt opgezocht via zijn login
User user;
try {
user = userRepository.findUserByLogin(login);
} catch (Exception e) {
throw new DaoException(168, e, simpleClassName);
}
// gevonden?
if (user == null) {
throw new UsernameNotFoundException(String.format("login [%s] inexistant", login));
}
// de gegevens van de gebruiker weergeven
return new AppUserDetails(user, userRepository);
}
}
- regel 18: injectie van de Spring-component [userRepository], waarmee de service de gebruiker kan weergeven op basis van zijn login, regel 27;
Uiteindelijk blijkt dat we alleen de [userRepository] nodig hebben en niet de twee andere repositories [roleRepository, userRoleRepository]. Deze zullen worden gebruikt in het volgende project, dat tot doel heeft de tabellen [USERS, ROLES, USERS_ROLES] te vullen.
20.4.6. De tests
De beveiligde webservice wordt gestart met de configuratie met de naam [spring-security-server-jpa-generic-hibernate-eclipselink] [1]. De test [JUnitTestDao] van de generieke client wordt gestart met de configuratie met de naam [spring-security-client-generic-JUnitTestDao] [2]:
![]() |
De tests zijn geslaagd.
20.5. Het Eclipse-project [spring-security-create-users]
![]() |
![]() |
20.5.1. De database
Bij het uitvoeren van het project worden de tabellen [USERS, ROLES, USERS_ROLES] gevuld vanuit de tabel [dbproduitscategories]:

![]() |
![]() |
De aangemaakte ID's [login/passwd] zijn de volgende: [admin/admin], [user/user], [guest/guest]. In de database zijn de wachtwoorden versleuteld.
![]() |

20.5.2. Maven-configuratie
Het project is een Maven-project dat is geconfigureerd via het volgende bestand: [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>dvp.spring.database</groupId>
<artifactId>spring-security-create-users-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-security-create-users-jpa</name>
<description>création de utilisateurs dans la base [dbproduitscategories]</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- spring-security-server-jpa-generic -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>spring-security-server-jpa-generic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- regels 22-25: afhankelijkheid van het Spring Security-framework. Het algoritme voor het versleutelen van wachtwoorden wordt door dit framework geleverd
- regels 27-31: afhankelijkheid van het project [spring-security-server-jpa-generic] dat we zojuist hebben gebouwd. Dit project implementeert de lagen [repositories] en [JPA] van het project;
Uiteindelijk zijn de afhankelijkheden als volgt:
![]() |
20.5.3. De laag [console]
![]() |
Aangezien de lagen [repositories] en [JPA] worden geïmplementeerd door de afhankelijkheid [spring-security-server-jpa-generic], hoeft alleen de laag [console] te worden geïmplementeerd.
![]() |
- [AppConfig] is de Spring-configuratieklasse van het project;
- [CreateUsers] is de uitvoerbare klasse die gebruikers en rollen aanmaakt;
- [Base64Encoder] is een ondersteunende klasse voor het genereren van de Base64-code van een [login, password]-paar. Deze hebben we al gebruikt. Ze is niet nodig voor dit project;
De Spring-configuratieklasse [AppConfig] is als volgt:
package spring.security.install;
import generic.jpa.config.ConfigJpa;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@Configuration
@EnableJpaRepositories(basePackages = { "spring.security.repositories" })
@Import({ ConfigJpa.class })
public class AppConfig {
}
- regel 10: hier wordt aangegeven waar de [repositories]-bestanden van de applicatie te vinden zijn. Deze bevinden zich in het pakket [spring.security.repositories] van de afhankelijkheid [spring-security-server-jpa-generic]
- regel 11: hier worden de beans geïmporteerd van de klasse [ConfigJpa], die de laag [JPA] van het project configureert. Deze klasse is te vinden in de afhankelijkheid [mysql-config-jpa-hibernate]:
![]() |
De klasse [CreateUsers] is als volgt:
package spring.security.install;
import generic.jpa.entities.dbproduitscategories.Role;
import generic.jpa.entities.dbproduitscategories.User;
import generic.jpa.entities.dbproduitscategories.UserRole;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.security.crypto.bcrypt.BCrypt;
import spring.security.repositories.RoleRepository;
import spring.security.repositories.UserRepository;
import spring.security.repositories.UserRoleRepository;
public class CreateUsers {
public static void main(String[] args) {
// einde
System.out.println("Travail en cours...");
// er worden drie gebruikers aangemaakt
String[] logins = { "admin", "user", "guest" };
String[] passwds = { "admin", "user", "guest" };
String[] roles = { "admin", "user", "guest" };
// Spring-context
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserRepository userRepository = context.getBean(UserRepository.class);
RoleRepository roleRepository = context.getBean(RoleRepository.class);
UserRoleRepository userRoleRepository = context.getBean(UserRoleRepository.class);
for (int i = 0; i < logins.length; i++) {
// we halen de gegevens van gebruiker nr. i op
String login = logins[i];
String password = passwds[i];
String roleName = String.format("ROLE_%s", roles[i].toUpperCase());
// bestaat de rol al?
Role role = roleRepository.findRoleByName(roleName);
// als deze niet bestaat, wordt deze aangemaakt
if (role == null) {
role = roleRepository.save(new Role(roleName));
}
// Bestaat de gebruiker al?
User user = userRepository.findUserByLogin(login);
// als deze niet bestaat, wordt deze aangemaakt
if (user == null) {
// het wachtwoord wordt gehasht met bcrypt
String crypt = BCrypt.hashpw(password, BCrypt.gensalt());
// de gebruiker wordt opgeslagen
user = userRepository.save(new User(null, null, login, login, crypt));
// we leggen de koppeling met de rol aan
userRoleRepository.save(new UserRole(user, role));
} else {
// de gebruiker bestaat al – heeft hij de gevraagde rol?
boolean trouvé = false;
for (Role r : userRepository.getRoles(user.getId())) {
if (r.getName().equals(roleName)) {
trouvé = true;
break;
}
}
// indien niet gevonden, wordt de koppeling met de rol aangemaakt
if (!trouvé) {
userRoleRepository.save(new UserRole(user, role));
}
}
}
// Spring-context afsluiten
context.close();
// einde
System.out.println("Travail terminé...");
}
}
- regels 22-24: definiëren de gebruikersnaam, het wachtwoord en de rol van drie gebruikers;
- regel 27: de Spring-context wordt opgebouwd op basis van de configuratieklasse [AppConfig];
- regels 28-30: we halen de referenties op van de drie [Repository] die we kunnen gebruiken om een gebruiker aan te maken;
- regel 31: de drie gebruikers worden aangemaakt;
- regels 33-35: de gegevens voor het aanmaken van gebruiker nr. i;
- regel 37: we controleren of de rol al bestaat;
- regels 39-41: als dat niet het geval is, maken we deze aan in de database. Deze krijgt een naam van het type [ROLE_XX];
- regel 43: we controleren of de login al bestaat;
- regels 45-52: als de login niet bestaat, wordt deze in de database aangemaakt;
- regel 47: het wachtwoord wordt versleuteld. Hiervoor wordt de klasse [BCrypt] van Spring Security gebruikt (regel 8). We hebben dus de bibliotheken van dit framework nodig. Het bestand [pom.xml] bevat deze afhankelijkheid:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- regel 49: de gebruiker wordt opgeslagen in de database;
- regel 51: evenals de relatie die hem aan zijn rol koppelt;
- regels 55-60: als de gebruiker al bestaat, wordt gekeken of de rol die we hem willen toewijzen al tot zijn rollen behoort;
- regel 62-64: als de gezochte rol niet is gevonden, wordt er een rij aangemaakt in de tabel [USERS_ROLES] om de gebruiker aan zijn rol te koppelen;
- er is geen bescherming ingebouwd tegen mogelijke uitzonderingen. Dit is een ondersteunende klasse om snel gebruikers aan te maken;
Om het project uit te voeren, voert men de uitvoeringsconfiguratie met de naam [spring-security-create-users-hibernate-eclipselink] uit:
![]() |
We hebben zojuist twee beveiligde webservices gebouwd:
- de ene met een [security / web / JDBC / MySQL]-architectuur;
- de andere met een architectuur [security / web / Hibernate / MySQL];
We gaan nu twee andere architecturen bekijken:
- een architectuur [security / web / EclipseLink / SQL Server 2014 Express];
- een architectuur [security / web / OpenJpa / Oracle Express];
20.5.4. Architectuur [security / web / EclipseLink / SQL Server]
![]() |
![]() |
- in [1] worden de projecten geladen die een laag [JDBC / SQL Server] en een laag [JPA / EclipseLink / SQL Server] configureren;
Opmerking: druk op Alt-F5 en genereer vervolgens alle Maven-projecten opnieuw.
We gaan ervan uit dat de SGBD SQL-server is gestart en dat de database [dbproduitscategories] is gegenereerd. Eerst moeten we de tabellen [USERS, ROLES, USERS_ROLES] in deze database vullen. Voer hiervoor de uitvoeringsconfiguratie met de naam [spring-security-create-users-hibernate-eclipselink] uit:
![]() | ![]() |
Deze moet de drie tabellen met gegevens vullen:
![]() | ![]() |
![]() |
![]() |
- start de beveiligde webservice met de configuratie met de naam [spring-security-server-jpa-generic-hibernate-eclipselink][1];
- start de test JUnitTestDao met de configuratie met de naam [spring-security-client-generic-JUnitTestDao][2]. Deze moet slagen [3] ;
![]() |
![]() |
20.5.5. Architectuur [security / web / OpenJpa / Oracle Express]
![]() |
![]() |
- in [1] worden de projecten geladen die een laag [JDBC / Oracle Express] en een laag [JPA / OpenJpa / Oracle Express] configureren;
Opmerking: druk op Alt-F5 en genereer vervolgens alle Maven-projecten opnieuw.
We gaan ervan uit dat de Oracle Express-instantie SGBD is gestart en dat de database [dbproduitscategories] is gegenereerd. We moeten eerst de tabellen [USERS, ROLES, USERS_ROLES] van deze database vullen. Voer hiervoor de uitvoeringsconfiguratie met de naam [spring-security-create-users-openjpa] uit:
![]() | ![]() |
Deze moet de drie tabellen met gegevens vullen:
![]() | ![]() |
![]() |
![]() |
- start de beveiligde webservice met de configuratie met de naam [spring-security-server-jpa-generic-openjpa][1-2];
- start de test JUnitTestDao met de configuratie met de naam [spring-security-client-generic-JUnitTestDao][3]. Deze moet slagen [4] ;
![]() |
![]() |



























































































