如何在Spring Boot Rest API中实现JWT和OAUTH2身份验证?

问题描述 投票:0回答:1

我正在Spring Boot中制作REST API,我需要对其进行保护。经过一些搜索,我发现了一些文章和教程,试图解释如何使用JWT和OAUTH2来验证安全的API,从而对应用程序进行身份验证,这会消耗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继续工作,并且即使使用String Secutiry依赖项,OAUTH2也没有给出任何已配置的迹象。

java spring-boot jwt spring-security-oauth2
1个回答
0
投票

尝试以下示例:带有jwt令牌认证和授权的Spring Boot👉

https://dzone.com/articles/spring-boot-security-json-web-tokenjwt-hello-world

© www.soinside.com 2019 - 2024. All rights reserved.