Build a Secure Spring Data JPA Resource Server

Build a Secure Spring Data JPA Resource Server

Use Spring Data JPA to build a resource server application that is secured with OAuth 2.0 and Spring Security.

Fahd Boudali

Great article, the thing that keeps scratching the back of my neck is, I still don’t see why I would use CrudRepository instead of JpaRepository ?
So I can have my repo and service behave like I want them to

Andrew Hughes

The JpaRepository provides some JPA-specific features such as batch deletes and flushing the persistence context. It is a superclass of CrudRepository (thus is does everything CrudRepository does and more). If you need the features that JpaRepository adds, then go ahead and use it. Or if you think you might need them. But if you don’t need those features, then my feeling is just to keep things simple and only add the implementations you are actually going to use.

neifi alcantara

Nice article, i’m junior developer and i can’t understand the use of controller class if JPA automatically create a resource server based in your domain model.

Matt Raible

You can use @RepositoryRestResource in small projects and demos and it’ll work just fine. However, exposing your entities (or tables) as an API is known as an anemic domain model and is not recommended for large and complex projects.

The fundamental horror of this anti-pattern is that it’s so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What’s worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about.

neifi alcantara

Thanks for the explanation Matt, now everything is clear!!

shantanu sardal

Great article! After changing the application to use JWT authorization, we also need to change the Controller method to use (@AuthenticationPrincipal Jwt jwtPrincipal) instead of (@AuthenticationPrincipal OidcUser oidcUser), otherwise the oidcUser object is going to be null.

Roman Korobitsin

Thank you for a super engaging guide. Absolutely loved the dinosaur analogy - now these concepts are stuck in my mind!

Thanks you for taking the time to put it all together in such an entertaining way.

Champs!

Matt Raible

Hello Fuad,

I published a video of this post on YouTube last week. Maybe that’ll help?

https://www.youtube.com/wat…

dariopunitech

It might be an off topic question.
Can I insert sql statements via JPA?
Specifically: set application_name='SOMETHING’
We would like to associate application code to sql operations, application_name could be useful to understand easily which app/module/operation has executed certain operations (long running queries, runtime errors, stats)

Andrew Hughes

Can you tell me a little about the context of when you would want the SQL code executed? On HTTP method calls? On entity reads and writes? JPA has a couple ways to write native queries that might do what you want, such as the @Query annotation and the EntityManager.createNativeQuery() method.

Rahul

Can you tell me how the tokens received while authorizing with an SPA can be used to validate the Spring Boot APIs?

Matt Raible

Which framework are you using to build your SPA?

Rahul

I’m using Angular 9.

Matt Raible

The messages.component.ts in our Angular sample shows how to do this:


export class MessagesComponent implements OnInit {
failed: Boolean;
messages: Array<message> ;

constructor(public oktaAuth: OktaAuthService, private http: HttpClient) {
this.messages = ;
}

async ngOnInit() {
const accessToken = this.oktaAuth.getAccessToken();
this.http.get(sampleConfig.resourceServer.messagesUrl, {
headers: {
Authorization: 'Bearer ’ + accessToken,
}
}).subscribe((data: any) => {
let index = 1;
const messages = data.messages.map((message) => {
const date = new Date(message.date);
const day = date.toLocaleDateString();
const time = date.toLocaleTimeString();
return {
date: ${day} ${time},
text: message.text,
index: index++
};
});
.push.apply(this.messages, messages);
}, (err) => {
console.error(err);
this.failed = true;
});
}
}

You also might check out my post on how to build a CRUD App with Angular 9 and Spring Boot 2.2.

Pranay Singhal

Starting with Spring Boot 2.5.0, this example will need “spring.jpa.defer-datasource-initialization=true” in /src/main/resources/application.properties to function properly.

Matt Raible

Thanks for the tip! I’ve updated this post with your recommendation.

If you’d like a t-shirt for your efforts, please email matt.raible@okta.com with your size and mailing address.