Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions exemplos/02-seguranca/docs/QUESTOES.ME
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
1 -


2 - Toda vez que uma requisição é realizada, a aplicação do lado do servidor interceptará o cabeçalho de autorização da requisição
e extrairá a informação do token. Uma consulta à base de dados será feita usando este token. Se ele for válido e possuir a
permissão necessário para acessar a área requisitada, tudo continuará. Caso contrário, será retornado um código de resposta do
tipo 403



3 - Não, a API não precisa ir até o banco de dados consultar as informações do usuário, pois contido no próprio token
já temos suas credenciais de acesso.
18 changes: 18 additions & 0 deletions exemplos/02-seguranca/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@
<version>42.2.8</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package br.com.ifpb.pweb2.securitydemo.config;

import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author raul on 27/10/19
*/
@Slf4j
public class JwtFilter extends BasicAuthenticationFilter {

private final SecurityConfig securityConfig;

public JwtFilter(AuthenticationManager authenticationManager, SecurityConfig securityConfig) {
super(authenticationManager);
this.securityConfig = securityConfig;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
if (authentication == null) {
filterChain.doFilter(request, response);
return;
}

SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}

private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if (token != null && !token.isEmpty() && token.startsWith("Bearer")) {
try {
String signingKey = securityConfig.getSecret();

Jws<Claims> parsedToken = Jwts.parser()
.setSigningKey(signingKey.getBytes())
.parseClaimsJws(token.replace("Bearer ", ""));

String username = parsedToken
.getBody()
.getSubject();

List<SimpleGrantedAuthority> authorities = ((List<?>) parsedToken.getBody()
.get("roles")).stream()
.map(authority -> new SimpleGrantedAuthority((String) authority))
.collect(Collectors.toList());

if (username != null && !username.isEmpty()){
return new UsernamePasswordAuthenticationToken(username, null, authorities);
}

} catch (ExpiredJwtException exception) {
log.warn("Request to parse expired JWT : {} failed : {}", token, exception.getMessage());
} catch (UnsupportedJwtException exception) {
log.warn("Request to parse unsupported JWT : {} failed : {}", token, exception.getMessage());
} catch (MalformedJwtException exception) {
log.warn("Request to parse invalid JWT : {} failed : {}", token, exception.getMessage());
} catch (SignatureException exception) {
log.warn("Request to parse JWT with invalid signature : {} failed : {}", token, exception.getMessage());
} catch (IllegalArgumentException exception) {
log.warn("Request to parse empty or null JWT : {} failed : {}", token, exception.getMessage());
}
}

return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package br.com.ifpb.pweb2.securitydemo.config;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author raul on 23/10/19
*/
@Configuration
public class JwtUtil {

private final SecurityConfig securityConfig;
private final String signingKey;

public JwtUtil(SecurityConfig securityConfig) {
this.securityConfig = securityConfig;
signingKey = securityConfig.getSecret();
}

public String generateToken(Authentication authentication) {
UserDetails user = ((UserDetails) authentication.getPrincipal());

List<String> roles = user.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());

return Jwts.builder()
.signWith(Keys.hmacShaKeyFor(signingKey.getBytes()), SignatureAlgorithm.HS512)
.setHeaderParam("type", securityConfig.getTokenType())
.setIssuer(securityConfig.getIssuer()) //emissor
.setAudience(securityConfig.getAudience()) //destinatario
.setSubject(user.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + securityConfig.getExpiration()))
.claim("roles", roles)
.compact();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package br.com.ifpb.pweb2.securitydemo.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
* @author raul on 23/10/19
*/
@Configuration
@ConfigurationProperties(prefix="security")
@Data
public class SecurityConfig {
private String tokenType;
private String secret;
private String issuer;
private String audience;
private Long expiration;
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,67 @@
package br.com.ifpb.pweb2.securitydemo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

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

public WebSecurityConfig() {
private final UserDetailsService userDetailsService;

private final PasswordEncoder passwordEncoder;

private final SecurityConfig securityConfig;

public WebSecurityConfig(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder, SecurityConfig securityConfig) {
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
this.securityConfig = securityConfig;
}


@Override
protected void configure(HttpSecurity http) throws Exception {
http
http.cors().and()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/publico").permitAll()
.antMatchers("/usuarios").hasRole("ADMIN")
.and()
.sessionManagement()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtFilter(authenticationManager(), securityConfig))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.and()
.and()
.csrf().disable();
}

public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}


@Bean
public AuthenticationManager getAuthenticationManager() throws Exception {
return authenticationManager();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package br.com.ifpb.pweb2.securitydemo.controller;

import lombok.Data;

/**
* @author raul on 25/10/19
*/
@Data
public class Login {

private String login;
private String password;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package br.com.ifpb.pweb2.securitydemo.controller;


import br.com.ifpb.pweb2.securitydemo.config.JwtUtil;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
* @author raul on 22/10/19
*/

@RestController
public class LoginController {

private final JwtUtil jwtUtil;

private final AuthenticationManager authenticationManager;

private final PasswordEncoder passwordEncoder;

public LoginController(AuthenticationManager authenticationManager, JwtUtil jwtUtil, PasswordEncoder passwordEncoder) {
this.jwtUtil = jwtUtil;
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
}

@PostMapping("login")
public ResponseEntity login(@RequestBody Login login) {

System.out.println(passwordEncoder.encode(login.getPassword()));

UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(login.getLogin(), login.getPassword());

String token = this.jwtUtil.generateToken(authenticationManager.authenticate(authenticationToken));

return ResponseEntity.ok(new Token(token));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package br.com.ifpb.pweb2.securitydemo.controller;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
* @author raul on 25/10/19
*/
@Data
@AllArgsConstructor
public class Token {
private String token;
}
Loading