Skip to content

Commit

Permalink
Merge pull request #4 from davidorellana98/develop
Browse files Browse the repository at this point in the history
Integration Security Jwt Authentication
  • Loading branch information
davidorellana98 authored Dec 19, 2022
2 parents ec2111e + 8cfe56e commit e05b298
Show file tree
Hide file tree
Showing 21 changed files with 454 additions and 45 deletions.
29 changes: 28 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.davidorellana</groupId>
Expand All @@ -17,16 +17,43 @@
<java.version>11</java.version>
</properties>
<dependencies>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

<!-- Security -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>

<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

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

<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.davidorellana.bookingsystemrestapi.auth.configuration;

import com.davidorellana.bookingsystemrestapi.auth.security.jwt.OperationJwt;
import com.davidorellana.bookingsystemrestapi.auth.security.jwt.OperationJwtImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConfigurationBeans {

@Bean
public OperationJwt generationToken() {
return new OperationJwtImpl();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.davidorellana.bookingsystemrestapi.auth.controller;

import com.davidorellana.bookingsystemrestapi.auth.dto.LoginDto;
import com.davidorellana.bookingsystemrestapi.auth.dto.TokenDto;
import com.davidorellana.bookingsystemrestapi.auth.security.jwt.OperationJwt;
import com.davidorellana.bookingsystemrestapi.user.model.data.User;
import com.davidorellana.bookingsystemrestapi.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.*;

@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
@RequestMapping("/v1/auth")
public class AuthenticationController {

private final OperationJwt operationJwt;
private final UserService userService;

@Autowired
private AuthenticationManager authenticationManager;


@Autowired
public AuthenticationController(OperationJwt operationJwt, UserService userService) {
this.operationJwt = operationJwt;
this.userService = userService;
}

@PostMapping
public ResponseEntity<TokenDto> generateJwt(@RequestBody LoginDto loginDto) {
User userFound = userService.findUserByEmail(loginDto.getEmail());
if (userFound != null) {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginDto.getEmail(), loginDto.getPassword()));
TokenDto tokenDto = operationJwt.generateTokenDto(userFound);
return new ResponseEntity<>(tokenDto, HttpStatus.OK);
}
return new ResponseEntity("Entry denied, due to incorrect credentials.", HttpStatus.NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.davidorellana.bookingsystemrestapi.auth.dto;

import java.io.Serializable;

public class LoginDto implements Serializable {

private static final long serialVersionUID = 1L;

private String email;
private String password;

public LoginDto() {
}

public LoginDto(String email, String password) {
this.email = email;
this.password = password;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.davidorellana.bookingsystemrestapi.auth.dto;

import java.io.Serializable;
import java.util.Date;

public class TokenDto implements Serializable {

private static final long serialVersionUID = 1L;

private String jwt;
private Date expirationJwt;

public TokenDto() { }

public TokenDto(String jwt, Date expirationJwt) {
this.jwt = jwt;
this.expirationJwt = expirationJwt;
}

public String getJwt() {
return jwt;
}

public void setJwt(String jwt) {
this.jwt = jwt;
}

public Date getExpirationJwt() {
return expirationJwt;
}

public void setExpirationJwt(Date expirationJwt) {
this.expirationJwt = expirationJwt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.davidorellana.bookingsystemrestapi.auth.security;

import com.davidorellana.bookingsystemrestapi.auth.security.jwt.JwtRequestFilter;
import com.davidorellana.bookingsystemrestapi.auth.service.UserDetailServiceAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailServiceAuth userDetailServiceAuth;

@Autowired
private JwtRequestFilter jwtRequestFilter;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailServiceAuth);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/v1/users" ).permitAll()
.antMatchers(HttpMethod.POST, "/v1/auth").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.davidorellana.bookingsystemrestapi.auth.security.jwt;

import com.davidorellana.bookingsystemrestapi.auth.service.UserDetailServiceAuth;
import com.davidorellana.bookingsystemrestapi.user.model.data.User;
import com.davidorellana.bookingsystemrestapi.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

@Autowired
private OperationJwt operationJwt;

@Autowired
private UserService userService;

@Autowired
private UserDetailServiceAuth userDetailServiceAuth;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer")){
String jwt = authorizationHeader.substring(7);
String idUser = operationJwt.extractSubject(jwt);

if (idUser != null && SecurityContextHolder.getContext().getAuthentication() == null){
User userFound = userService.findUserById(idUser);

if (operationJwt.validateJwt(jwt, userFound)){
UserDetails userDetails = userDetailServiceAuth.loadUserByUsername(userFound.getEmail());
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails
,null
,userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource()
.buildDetails(request));

SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}

filterChain.doFilter(request, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.davidorellana.bookingsystemrestapi.auth.security.jwt;

import com.davidorellana.bookingsystemrestapi.auth.dto.TokenDto;
import com.davidorellana.bookingsystemrestapi.user.model.data.User;
import io.jsonwebtoken.Claims;

import java.util.Calendar;

public interface OperationJwt {

String generateJwt(User user, Calendar expirationDate);
TokenDto generateTokenDto(User user);
Boolean validateJwt(String jwt, User user);
Claims returnClaims(String jwt);
String extractSubject(String jwt);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.davidorellana.bookingsystemrestapi.auth.security.jwt;

import com.davidorellana.bookingsystemrestapi.auth.dto.TokenDto;
import com.davidorellana.bookingsystemrestapi.user.model.data.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;

import java.util.Calendar;
import java.util.Date;

public class OperationJwtImpl implements OperationJwt {

@Value("${KEY_SECRET}")
private String keySecret;

private final Integer MINUTES_JWT_EXPIRATION = 45;

@Override
public String generateJwt(User user, Calendar expirationDate) {

return Jwts.builder()
.setSubject(user.getId())
.claim("name", user.getName())
.setIssuedAt(new Date())
.setExpiration(expirationDate.getTime())
.signWith(SignatureAlgorithm.HS256, keySecret)
.compact();
}

@Override
public TokenDto generateTokenDto(User user) {
Calendar dateExpiration = Calendar.getInstance();
dateExpiration.add(Calendar.MINUTE, MINUTES_JWT_EXPIRATION);
String jwt = generateJwt(user, dateExpiration);
return new TokenDto(jwt, dateExpiration.getTime());
}

@Override
public Boolean validateJwt(String jwt, User user) {
Boolean isJwtExpired = returnClaims(jwt).getExpiration().before(new Date());
return user.getId().equals(extractSubject(jwt)) && !isJwtExpired;
}

@Override
public Claims returnClaims(String jwt) {
return Jwts.parser()
.setSigningKey(keySecret)
.parseClaimsJws(jwt)
.getBody();
}

@Override
public String extractSubject(String jwt) {
return returnClaims(jwt).getSubject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.davidorellana.bookingsystemrestapi.auth.service;

import com.davidorellana.bookingsystemrestapi.user.model.data.User;
import com.davidorellana.bookingsystemrestapi.user.repository.UserRepositoryDao;
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 java.util.ArrayList;

@Service
public class UserDetailServiceAuth implements UserDetailsService {

@Autowired
private UserRepositoryDao userRepositoryDao;

@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User userFound = userRepositoryDao.findUserByEmail(email);
return new org.springframework.security.core.userdetails.User(
userFound.getEmail(), "{noop}" + userFound.getPassword(), new ArrayList<>()
);
}
}
Loading

0 comments on commit e05b298

Please sign in to comment.