I try to do the security of my project adapting the baeldung documentation and the previous code, and I want to know the normal method of this. I have the following configuration
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {
@Autowired
private UserDetailsService customUserDetailsService;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity httpSecurity) throws Exception{
return httpSecurity.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder)
.and()
.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.cors()
.and()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/user/create", "/api/login", "/swagger-ui/**", "/v3/api-docs/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
then I have this token provider
@Component
public class JtwTokenProvider {
@Value("${app.jwt-secret}")
private String jwtSecret;
@Value("${app.jwt-expiration-milliseconds}")
private int jwtExpirationInMs;
public String generateToken(Authentication authentication) {
String username = authentication.getName();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
String token = Jwts.builder().setSubject(username).setIssuedAt(new Date())
.setExpiration(expiryDate).signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
return token;
}
public String getUsernameOfJwt(String token){
Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
return claims.getSubject();
}
public boolean validateToken(String token){
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
}catch (SignatureException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid JWT signature");
}catch (MalformedJwtException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid JWT token");
}catch (ExpiredJwtException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Expired JWT token");
}catch (UnsupportedJwtException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported JWT token");
}catch (IllegalArgumentException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "JWT claims string is empty");
}
}
}
The token filter is the same and this manner is okay? What others exist?
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JtwTokenProvider tokenProvider;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//Get JWT from request
String token = getJwtFromRequest(request);
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
// Get username from token
String username = tokenProvider.getUsernameOfJwt(token);
// Load user associated with the token
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//Set the authentication in the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.replace("Bearer ", "");
}
return null;
}
}
Then I used the userdetails service
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username).orElseThrow(
() -> new NotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), getAuthority(user.getRoles()));
}
private Collection<? extends GrantedAuthority> getAuthority(Set<Role> roles){
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}
Finally here is my authentication, this is safe? what is the standart manner of do the same?
@Service
public class LoginServiceImpl implements LoginService{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JtwTokenProvider jwtTokenProvider;
@Override
public JwtAuthResponse login(LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(),
loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtTokenProvider.generateToken(authentication);
return new JwtAuthResponse(jwt);
}
}
I was waiting your responses thanks :D