'authenticate: Unauthorized -> spring with jwt token
URL : localhost:8085/authenticate . Post method, body {"email" :...., "password"}.
"trace": "org.springframework.security.authentication.InternalAuthenticationServiceException: No value present\r\n\tat org.
Same trece with password and without password in body. Status 401, error: "Unauthorized".
AppUserRole: enum, contains ADMIN and USER.
Prop config-> spring. main. allow-circular-references= true
User Schema
@Getter
@Setter
@NoArgsConstructor
@Entity
public class AppUser implements UserDetails {
@SequenceGenerator(
name = "student_sequence",
sequenceName = "student_sequence",
allocationSize = 1
)
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "student_sequence"
)
private Long id;
private String firstName;
private String lastName;
@Column(name = "email", nullable = false)
private String email;
@Column(name = "password", nullable = false)
private String password;
@Enumerated(EnumType.STRING)
private AppUserRole appUserRole;
private Boolean locked = false;
private Boolean enabled = false;
@Column(name = "reset_token")
private String resetToken;
public AppUser(String firstName,
String lastName,
String email,
String password,
AppUserRole appUserRole
) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.appUserRole = appUserRole;
}
public void setFields(DtoUser dtoUser) {
this.appUserRole = dtoUser.getAppUserRole();
this.email = dtoUser.getEmail();
this.enabled = dtoUser.getEnabled();
this.firstName = dtoUser.getFirstName();
this.lastName = dtoUser.getLastName();
this.locked = dtoUser.getLocked();
this.password = dtoUser.getPassword();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority authority =
new SimpleGrantedAuthority(appUserRole.name());
return Collections.singletonList(authority);
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return email;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getResetToken() {
return resetToken;
}
public void setResetToken(String resetToken) {
this.resetToken = resetToken;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
AppUserRepository
@Repository
@Transactional(readOnly = true)
public interface AppUserRepository
extends JpaRepository<AppUser, Long> {
Optional<AppUser> findByEmail(String email);
Optional<AppUser> findByResetToken(String resetToken);
@Transactional
@Modifying
@Query("UPDATE AppUser a " +
"SET a.enabled = TRUE WHERE a.email = ?1")
int enableAppUser(String email);
}
JWT Service
@Service
public class JwtService implements UserDetailsService {
@Autowired
private JwtUtil jwtUtil;
private AppUserRole appUserRole;
@Autowired
private AppUserRepository appUserRepository;
@Autowired
private AuthenticationManager authenticationManager;
public JwtResponse createJwtToken(JwtRequest jwtRequest) throws Exception {
String email = jwtRequest.getUserName();
String password = jwtRequest.getUserPassword();
authenticate(email, password);
UserDetails userDetails = loadUserByUsername(email);
String newGeneratedToken = jwtUtil.generateToken(userDetails);
AppUser user = appUserRepository.findByEmail(email).get();
return new JwtResponse(user, newGeneratedToken);
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
AppUser user = appUserRepository.findByEmail(email).get();
if (user != null) {
return new org.springframework.security.core.userdetails.User(
user.getEmail(),
user.getPassword(),
getAuthority(user)
);
} else {
throw new UsernameNotFoundException("User not found with username: " + email);
}
}
private Set getAuthority(AppUser user) {
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority(appUserRole.name()));
return authorities;
}
private void authenticate(String email, String password) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, password));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
}
}
JWT Util
@Component
public class JwtUtil {
private static final String SECRET_KEY = "onlinevehicleshopSECRETKEY_123456";
private static final int TOKEN_VALIDITY = 3600 * 5;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
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_KEY).parseClaimsJws(token).getBody();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
}
JWT Controller
@RestController
@CrossOrigin
public class JwtController {
@Autowired
private JwtService jwtService;
@PostMapping({"/authenticate"})
public JwtResponse createJwtToken(@RequestBody JwtRequest jwtRequest) throws Exception {
return jwtService.createJwtToken(jwtRequest);
}
}
JWT Request
public class JwtRequest {
private String email;
private String password;
public String getUserName() {
return email;
}
public void setUserName(String email) {
this.email = email;
}
public String getUserPassword() {
return password;
}
public void setUserPassword(String password) {
this.password = password;
}
}
JWT Response
public class JwtResponse {
private AppUser appUser;
private String jwtToken;
public JwtResponse(AppUser appUser, String jwtToken) {
this.appUser = appUser;
this.jwtToken = jwtToken;
}
public AppUser getUser() {
return appUser;
}
public void setUser(AppUser appUser) {
this.appUser = appUser;
}
public String getJwtToken() {
return jwtToken;
}
public void setJwtToken(String jwtToken) {
this.jwtToken = jwtToken;
}
}
Cors Configuration
@Configuration
public class CorsConfiguration {
private static final String GET = "GET";
private static final String POST = "POST";
private static final String PUT = "PUT";
private static final String DELETE = "DELETE";
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods(GET, POST, PUT, DELETE)
.allowedHeaders("*")
.allowedOriginPatterns("*")
.allowCredentials(true);
}
};
JwtAuthenticationEntryPoint
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
JWT Request filter
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private JwtService jwtService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String email = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
email = jwtUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
System.out.println("JWT token does not start with Bearer");
}
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = jwtService.loadUserByUsername(email);
if (jwtUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
Web Sercurity config
@Configuration
@AllArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final AppUserService appUserService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
private UserDetailsService jwtService;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors();
httpSecurity
.csrf().disable()
.authorizeRequests()
.antMatchers("**" )
.permitAll()
.anyRequest()
.authenticated().and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(jwtService).passwordEncoder(passwordEncoder());
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
