Как я могу реализовать аутентификацию JWT и OAUTH2 в моем Spring Boot Rest API? - PullRequest
0 голосов
/ 07 ноября 2019

Я делаю REST API в Spring Boot, и мне нужно его защитить. После некоторых поисков я нашел несколько статей и учебных пособий, в которых пытались объяснить, как создать безопасный API с использованием JWT и OAUTH2 для аутентификации приложения, которое потребляет ресурсы API и пользователей, использующих эти приложения, но я не очень понялну, потому что я впервые это увидел.

Я реализовал код, который выполняет аутентификацию JWT, но для работы некоторых конечных точек должен быть разрешен доступ из любого места, и это очень плохо, я думаю,Когда я пытался реализовать аутентификацию OAUTH2, чтобы исправить это, это не сработало.

Код для реализации аутентификации JWT выглядит так: Извините, если это слишком много кода, но, как я уже сказал, я не уверен, какэто работает, и мне нужно понять.

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

    private static final long serialVersionUID = -7858869558953243875L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            org.springframework.security.core.AuthenticationException authException)
            throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "token");

    }
}
@Component
public class JWTRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;
    @Autowired
    private JwtTokenUtill jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String requestTokenHeader = request.getHeader("token") == null ? request.getParameter("token") : request.getHeader("token");
        String username = null;
        String jwtToken = null;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS, PATCH");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, token, Content-Type, Authorization, credential, X-XSRF-TOKEN, ");

        if (requestTokenHeader != null) {
            jwtToken = requestTokenHeader;
            try {

                username = jwtTokenUtil.getUsernameFromToken(jwtToken);

            } catch (IllegalArgumentException e) {
                System.out.println("Não foi possível obter o token JWT");
            } catch (ExpiredJwtException e) {
                System.out.println("O token JWT expirou");
            }
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);

            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}
@Component
public class JwtTokenUtill implements Serializable {

    private static final long serialVersionUID = -2550185165626007488L;
    public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;

    @Value("${jwt.secret}")
    private String secret;

    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    public String generateTokenCliente(Cliente cliente) {
        Map<String, Object> claims = new HashMap<>();
        return doGenerateToken(claims, cliente.getEmail(), cliente.getIdCliente());
    }

    public String generateTokenProfissional(Profissional profissional) {
        Map<String, Object> claims = new HashMap<>();
        return doGenerateToken(claims, profissional.getEmail(), profissional.getIdProfissional());
    }

    private String doGenerateToken(Map<String, Object> claims, String subject, Long id) {
        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
                .signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);

        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
}
@Service
public class JwtUserDetailsService implements UserDetailsService {

    @Autowired
    ClienteDTORepository clienteRepository;

    @Autowired
    ProfissionalDTORepository profissionalRepository;


    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

        ClienteDTO cliente = clienteRepository.findByEmail(email);
        ProfissionalDTO profissional = profissionalRepository.findByEmail(email);

        if (cliente != null) {
            User user = new User(cliente.getEmail(), cliente.getIdCliente().toString(), new ArrayList<>());

            return user;
        } else if (profissional != null) {
            User user = new User(profissional.getEmail(), profissional.getIdProfissional().toString(), new ArrayList<>());

            return user;

        }

        throw new UsernameNotFoundException("Usuário com e-mail "+email+" não foi encontrado.");
    }
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Autowired
    private JWTRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("kelvin").password("123").roles("ADMIN");
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
        .authorizeRequests(
        .antMatchers(HttpMethod.POST, "/auth/**").permitAll()
        .anyRequest().authenticated()
        .and().exceptionHandling()
        .authenticationEntryPoint(jwtAuthenticationEntryPoint)
        .and().sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}
public class JWTRequest implements Serializable {
    private static final long serialVersionUID = 5926468583005150707L;
    private String email;
    private String senha;

    public JWTRequest() {
    }

    public JWTRequest(String email, String senha) {
        this.setEmail(email);
        this.setSenha(senha);
    }

    public String getEmail() {
        return email;
    }

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

    public String getSenha() {
        return this.senha;
    }

    public void setSenha(String senha) {
        this.senha = senha;
    }
}
public class JWTResponse implements Serializable {

    private static final long serialVersionUID = -8091879091924046844L;
    private final String jwttoken;

    public JWTResponse(String jwttoken) {
        this.jwttoken = jwttoken;
    }

    public String getToken() {
        return this.jwttoken;
    }
}
@RestController
@CrossOrigin(origins = "http://localhost:3000")
@SupportedOptions(value = { "eventBusIndex", "verbose" })
public class JwtAuthenticationResource {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtTokenUtill jwtTokenUtil;

    @Autowired
    private ClienteRepository clienteRepository;

    @Autowired
    private ProfissionalRepository profissionalRepository;


    @PostMapping("/login/cliente")
    public ResponseEntity<?> createAuthenticationTokenCliente(@RequestBody JWTRequest authenticationRequest)
            throws Exception {
        final Cliente cliente = clienteRepository.findUserLogin(
                authenticationRequest.getEmail(),
                authenticationRequest.getSenha());

        if (cliente != null) {
            final String token = jwtTokenUtil.generateTokenCliente(cliente);
            return ResponseEntity.ok(new JWTResponse(token));
        }

        return ResponseEntity.ok("{\"error\": \"Usuario não cadastrado\"}");
    }

    @PostMapping("/login/profissional")
    public ResponseEntity<?> createAuthenticationTokenProfissional(@RequestBody JWTRequest authenticationRequest)
            throws Exception {
        final Profissional profissional = profissionalRepository.findUserLogin(
                authenticationRequest.getEmail(), 
                authenticationRequest.getSenha());

        if (profissional != null) {
            final String token = jwtTokenUtil.generateTokenProfissional(profissional);
            return ResponseEntity.ok(new JWTResponse(token));
        }

        return ResponseEntity.ok("{\"error\": \"Usuario não cadastrado\"}");
    }



    private void authenticate(String username, String password) throws Exception {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (DisabledException e) {
            throw new Exception("USER_DISABLED", e);
        } catch (BadCredentialsException e) {
            throw new Exception("INVALID_CREDENTIALS", e);
        }
    }


}

Классы Profissional и Cliente, которые появляются в коде, являютсяпользователи из моего приложения.

С этим кодом работает реализация JWT, но я не могу реализовать OAUTH2 для аутентификации приложения, использующего API.

Когда я пытался сделатьOAUTH2 работает, ничего не произошло, JWT продолжал работать, и OAUTH2 не дал никаких признаков того, что он был настроен, даже с зависимостями String Secutiry.

...