Show Aprenda Quarkus e Desenvolva API's RESTful Poderosas em JavaAprenda de vez o framework Java Subatômico Quarkus para criar API's RESTful poderosas e robustas. CUPOM Fullstack Next.js + Spring Boot, React, TS e Jasper ReportsDesenvolva um sistema de vendas completa do zero até a nuvem através da integração da dessa stack. Cupom Angular e Spring Boot Fullstack completo e atualizadoDesenvolva 2 aplicações completas através da integração da stack Angular e Spring Boot. Cupom Spring Boot + React JS: Desenvolva Aplicações Web CompletasCurso Full Stack com Spring Boot e React JS, do zero à nuvem. Cupom Design de API's RestFul com Spring Boot, TDD e o novo JUnit5API's RestFul de alto nível com Spring Boot utilizando TDD e o novo JUnit 5. Cupom Spring Boot Expert: JPA, RESTFul API, Security, JWT e MaisDo Zero ao Expert em Spring Boot e todo o ecossistema Spring. Guia Completo e atualizado. Cupom Angular 10 + Spring Boot com deploy no Heroku e Github pagesAprenda a integrar o framework front end Angular 10 com uma API REST em Java utilizando Spring Boot do absoluto zero. Cupom React + Redux, Bootstrap, Material UI e API's Rest CompletoDomine o React + Redux com Bootstrap e Material Design COM API's Rest. Cupom This article is a guide on how to setup a server-side implementation of JSON Web Token (JWT) - OAuth2 authorization framework using Spring Boot and Maven. An initial grasp on OAuth2 is recommended and can be obtained reading the draft linked above or searching for useful information on the web like this or this. OAuth2 is an authorization framework superseding it first version OAuth, created back in 2006. It defines the authorization flows between clients and one or more HTTP services in order to gain access to protected resources. OAuth2 defines the following server-side roles:
JSON Web Token, or JWT, is a specification for the representation of claims to be transferred between two parties. The claims are encoded as a JSON object used as the payload of an encrypted structure, enabling the claims to be digitally signed or encrypted. The containing structure can be JSON Web Signature (JWS) or JSON Web Encryption (JWE). JWT can be chosen as the format for access and refresh tokens used inside the OAuth2 protocol. OAuth2 and JWT gained a huge popularity over the last years because of the following features:
However, OAuth2 and JWT are not always the best choice in case the following considerations are important for the project:
Expected Protocol FlowWhile one of the main features of OAuth2 is the introduction of an authorization layer in order to separate authorization process from resource owners, for the sake of simplicity, the article’s outcome is the build of a single application impersonating all resource owner, authorization server, and resource server roles. Because of this, the communication will flow between two entities only, the server and the client. This simplification should help to focus on the aim of the article, i.e. the setup of such a system in a Spring Boot’s environment. The simplified flow is described below:
Spring Security and Spring BootFirst of all, a brief introduction to the technology stack selected for this project. The project management tool of choice is Maven, but due to the project’s simplicity, it should not be difficult to switch to other tools like Gradle. In the article’s continuation, we focus on Spring Security aspects only, but all code excerpts are taken from a fully working server-side application which source code is available in a public repository along with a client consuming its REST resources. Spring Security is a framework providing an almost declarative security services for Spring-based applications. Its roots are from the first beginning of Spring and it’s organized as a set of modules due to the high number of different security technologies covered. Let’s take a quick look at Spring Security architecture (a more detailed guide can be found here). Security is mostly about authentication, i.e. the verification of the identity, and authorization, the grant of access rights to resources. Spring security supports a huge range of authentication models, either provided by third parties or implemented natively. A list can be found here. Regarding authorization, three main areas are identified:
AuthenticationThe basic interface is AuthenticationManager which is responsible to provide an authentication method. The UserDetailsService is the interface related to user’s information collection, which could be directly implemented or used internally in case of standard JDBC or LDAP methods. The main interface is AccessDecisionManager; which implementations for all three areas listed above delegate to a chain of AccessDecisionVoter. Each instance of the latter interface represents an association between an Authentication (a user identity, named principal), a resource and a collection of ConfigAttribute, the set of rules which describes how the resource’s owner allowed the access to the resource itself, maybe through the use of user roles. The security for a web application is implemented using the basic elements described above in a chain of servlet filters, and the class WebSecurityConfigurerAdapter is exposed as a declarative way to express resource’s access rules. Method security is first enabled by the presence of the @EnableGlobalMethodSecurity(securedEnabled = true) annotation, and then by the use of a set of specialized annotations to apply to each method to be protected such as @Secured, @PreAuthorize, and @PostAuthorize. Spring Boot adds to all of this a collection of opinionated application configurations and third-party libraries in order to ease the development while maintaining an high quality standard. JWT OAuth2 with Spring BootLet’s now move on the original problem to set up an application implementing OAuth2 and JWT with Spring Boot. While multiple server-side OAuth2 libraries exist in the Java world (a list can be found here), the spring-based implementation is the natural choice as we expect to find it well integrated into Spring Security architecture and therefore avoid the need to handle much of the low-level details for its use. All security-related library dependencies are handled by Maven with the help of Spring Boot, which is the only component requiring an explicit version inside maven’s configuration file pom.xml (i.e. library versions are automatically inferred by Maven choosing the most up-to-date version compatible with the inserted Spring Boot version). Find below the excerpt from maven’s configuration file pom.xml containing the dependencies related to Spring Boot security: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.1.0.RELEASE</version> </dependency>The app acts both as OAuth2 authorization server/resource owner and as resource server. The protected resources (as resource server) are published under /api/ path, while authentication path (as resource owner/authorization server) is mapped to /oauth/token, following proposed default. App’s structure:
Next paragraphs cover the configuration for each one of the three OAuth2 roles mentioned above. The related classes are inside security package:
Authorization server behavior is enabled by the presence of @EnableAuthorizationServer annotation. Its configuration is merged with the one related to the resource owner behavior and both are contained in the class AuthorizationServerConfigurerAdapter. The configurations applied here are related to:
The next section describes the configuration to apply to the resource server. Setup for Resource ServerThe resource server behavior is enabled by the use of @EnableResourceServer annotation and its configuration is contained in the class ResourceServerConfiguration. The only needed configuration here is the definition of resource identification in order to match the client’s access defined in the previous class. package net.reliqs.gleeometer.security; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; @Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) { resources.resourceId("api"); } }The last configuration element is about the definition of web application security. Web Security SetupSpring web security configuration is contained in the class ServerSecurityConfig, enabled by the use of @EnableWebSecurity annotation. The @EnableGlobalMethodSecurity permits to specify security on the method level. Its attribute proxyTargetClass is set in order to have this working for RestController’s methods, because controllers are usually classes, not implementing any interfaces. It defines the following:
The code extract below is about the implementation of UserDetailsService interface in order to provide the resource owner’s authentication. package net.reliqs.gleeometer.security; import net.reliqs.gleeometer.users.User; import net.reliqs.gleeometer.users.UserRepository; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; 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; @Service public class UserService implements UserDetailsService { private final UserRepository repository; public UserService(UserRepository repository) { this.repository = repository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = repository.findByEmail(username).orElseThrow(() -> new RuntimeException("User not found: " + username)); GrantedAuthority authority = new SimpleGrantedAuthority(user.getRole().name()); return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), Arrays.asList(authority)); } }The next section is about the description of a REST controller implementation in order to see how security constraints are mapped. REST ControllerInside the REST controller we can find two ways to apply access control for each resource method:
ConclusionSpring Security and Spring Boot permit to quickly set up a complete OAuth2 authorization/authentication server in an almost declarative manner. The setup can be further shortened by configuring OAuth2 client’s properties directly from application.properties/yml file, as explained in this tutorial. All source code is available in this GitHub repository: spring-glee-o-meter. An Angular client which consumes the published resources can be found in this GitHub repository: glee-o-meter. |