feat: add auth filters
This commit is contained in:
parent
5fa28df29c
commit
dde80231d8
@ -0,0 +1,72 @@
|
||||
package dev.gfxv.blps.security;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
JwtUtils jwtUtils;
|
||||
|
||||
@Autowired
|
||||
public JwtAuthenticationFilter(JwtUtils jwtUtils) {
|
||||
this.jwtUtils = jwtUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain
|
||||
) throws ServletException, IOException {
|
||||
try {
|
||||
String jwt = parseJwt(request);
|
||||
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
|
||||
String username = jwtUtils.getUsernameFromJwtToken(jwt);
|
||||
List<String> roles = jwtUtils.getRolesFromJwtToken(jwt);
|
||||
|
||||
List<SimpleGrantedAuthority> authorities = roles.stream()
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||
username, null, authorities);
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO: add error logging
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private String parseJwt(HttpServletRequest request) {
|
||||
String headerAuth = request.getHeader("Authorization");
|
||||
|
||||
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
|
||||
return headerAuth.substring(7);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
72
src/main/java/dev/gfxv/blps/security/JwtUtils.java
Normal file
72
src/main/java/dev/gfxv/blps/security/JwtUtils.java
Normal file
@ -0,0 +1,72 @@
|
||||
package dev.gfxv.blps.security;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class JwtUtils {
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
|
||||
public String generateJwtToken(Authentication authentication) {
|
||||
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
|
||||
|
||||
List<String> roles = userPrincipal.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(userPrincipal.getUsername())
|
||||
.claim("roles", roles)
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(new Date((new Date()).getTime() + jwtExpiration))
|
||||
.signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes()), SignatureAlgorithm.HS512)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String getUsernameFromJwtToken(String token) {
|
||||
return Jwts.parserBuilder()
|
||||
.setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes()))
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody()
|
||||
.getSubject();
|
||||
}
|
||||
|
||||
public List<String> getRolesFromJwtToken(String token) {
|
||||
Claims claims = Jwts.parserBuilder()
|
||||
.setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes()))
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
return claims.get("roles", List.class);
|
||||
}
|
||||
|
||||
public boolean validateJwtToken(String authToken) {
|
||||
try {
|
||||
Jwts.parserBuilder()
|
||||
.setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes()))
|
||||
.build()
|
||||
.parseClaimsJws(authToken);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
// TODO: add error logging
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
src/main/java/dev/gfxv/blps/security/UserDetailsImpl.java
Normal file
81
src/main/java/dev/gfxv/blps/security/UserDetailsImpl.java
Normal file
@ -0,0 +1,81 @@
|
||||
package dev.gfxv.blps.security;
|
||||
|
||||
import dev.gfxv.blps.entity.User;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
public class UserDetailsImpl implements UserDetails {
|
||||
Long id;
|
||||
String username;
|
||||
String email;
|
||||
String password;
|
||||
Collection<? extends GrantedAuthority> authorities;
|
||||
|
||||
public UserDetailsImpl(Long id, String username, String email, String password,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
public static UserDetailsImpl build(User user) {
|
||||
List<GrantedAuthority> authorities = user.getRoles().stream()
|
||||
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new UserDetailsImpl(
|
||||
user.getId(),
|
||||
user.getUsername(),
|
||||
user.getEmail(),
|
||||
user.getPassword(),
|
||||
authorities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package dev.gfxv.blps.service;
|
||||
|
||||
import dev.gfxv.blps.entity.User;
|
||||
import dev.gfxv.blps.repository.UserRepository;
|
||||
import dev.gfxv.blps.security.UserDetailsImpl;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
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;
|
||||
|
||||
@Service
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
public UserDetailsServiceImpl(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
User user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
|
||||
return UserDetailsImpl.build(user);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user