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