Below you will find the 2 classes that I think you guys need. If any more info is required please let me know.
AuthService
package com.r.reservationproject.services;
import com.r.reservationproject.dto.AuthenticationResponse;
import com.r.reservationproject.dto.RegisterRequest;
import com.r.reservationproject.domain.NotificationEmail;
import com.r.reservationproject.domain.User;
import com.r.reservationproject.domain.VerificationToken;
import com.r.reservationproject.dto.LoginRequest;
import com.r.reservationproject.exceptions.SpringReservationAccountException;
import com.r.reservationproject.repositories.UserRepo;
import com.r.reservationproject.repositories.VerificationTokenRepo;
import com.r.reservationproject.security.JwtProvider;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotBlank;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
#Service
#AllArgsConstructor
#Transactional
// Contains logic to create username password authentication token and use authenticationManager to perform login
public class AuthService {
private final PasswordEncoder passwordEncoder;
private final UserRepo userRepo;
private final VerificationTokenRepo verificationTokenRepo;
private final MailService mailService;
private final AuthenticationManager authenticationManager;
private final JwtProvider jwtProvider;
public void signup(RegisterRequest registerRequest) {
User user = new User();
user.setUsername(registerRequest.getUsername());
user.setEmail(registerRequest.getEmail());
user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
user.setCreated(Instant.now());
user.setEnabled(false);
userRepo.save(user);
String token = generateVerificationToken(user);
mailService.sendMail(new NotificationEmail("Activeren account applicatie", user.getEmail(),
"Bedankt voor het gebruiken van onze applicatie, om uw account te activeren vragen wij u om volgende link te klikken :" +
"http://localhost:8080/api/auth/accountVerification/" + token));
}
private String generateVerificationToken(User user) {
String token = UUID.randomUUID().toString();
VerificationToken verificationToken = new VerificationToken();
verificationToken.setToken(token);
verificationToken.setUser(user);
verificationTokenRepo.save(verificationToken);
return token;
}
public void verifyAccount(String token) {
Optional<VerificationToken> verificationToken = verificationTokenRepo.findByToken(token);
verificationToken.orElseThrow(() -> new SpringReservationAccountException("Token is niet geldig"));
fetchUserAndEnable(verificationToken.get());
}
public void fetchUserAndEnable(VerificationToken verificationToken) {
#NotBlank(message = "Username is required") String username = verificationToken.getUser().getUsername();
User user = userRepo.findByUsername(username).orElseThrow(() -> new SpringReservationAccountException("Gebruiker onbekend"));
user.setEnabled(true);
userRepo.save(user);
}
public AuthenticationResponse login(LoginRequest loginRequest) {
Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authenticate);
String token = jwtProvider.generateToken(authenticate);
// to send this token we use a dto (authenticationresponse)
return new AuthenticationResponse(token, loginRequest.getUsername());
}
}
SecurityConfig
package com.r.reservationproject.config;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#EnableWebSecurity
#AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.anyRequest()
.authenticated();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
}
Full error:
APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in com.r.reservationproject.services.AuthService required a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' in your configuration.
I don't get the error since I already defined the Bean in the SecurityConfig
I appreciate your help a lot!
Try adding #Configuration annotation in your SecurityConfig class
I want to require authentication for my endpoints that start with "/chat/..." (on GET requisitions). I have done some basic configuration but it doesn't seem to be working. Even after authenticating a user and using its generated JWT Token, Postman still returns code 403 (Forbidden) for me. What could I be doing wrong?
My SecurityConfig class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private Environment env;
#Autowired
private JWTUtil jwtUtil;
private static final String[] PUBLIC_MATCHERS_GET = {
"/usuarios/**",
};
private static final String[] PUBLIC_MATCHERS = {
"/login/**"
};
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests()
.antMatchers(HttpMethod.GET, PUBLIC_MATCHERS_GET).permitAll()
.antMatchers(PUBLIC_MATCHERS).permitAll()
.antMatchers(HttpMethod.GET, "/chat/**").authenticated()
.anyRequest().authenticated();
http.addFilter(new JWTAuthenticationFilter(authenticationManager(), jwtUtil));
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
My ChatController class:
import com.example.chatonline.domain.Mensagem;
import com.example.chatonline.domain.Usuario;
import com.example.chatonline.services.ChatService;
import com.example.chatonline.services.UsuarioService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping(value = "/chat")
public class ChatController {
#Autowired
private ChatService chatService;
#Autowired
UsuarioService usuarioService;
#PreAuthorize("isAuthenticated()")
#GetMapping(value = "/usuarios")
public ResponseEntity<List<Usuario>> findOnlineUsers(){
List<Usuario> usuarios = usuarioService.findByOnlineUsers();
return ResponseEntity.ok().body(usuarios);
}
#PreAuthorize("isAuthenticated()")
#GetMapping(value = "/mensagens")
public ResponseEntity<List<Mensagem>> findMessages(){
List<Mensagem> obj = chatService.findMessages();
return ResponseEntity.ok().body(obj);
}
#PostMapping
public ResponseEntity<Void> insertMessage(#RequestBody Mensagem obj){
obj = chatService.insertMessage(obj);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
#RequestMapping(value = "/mensagens/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deleteMessage(#PathVariable Integer id){
chatService.deleteMessage(id);
return ResponseEntity.noContent().build();
}
}
Can any one suggest me another solution or how i can fixed this issue please.and thank's by advance
cotroller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.JwtRequest;
import com.example.demo.entity.JwtResponse;
import com.example.demo.service.JwtService;
#RestController
#CrossOrigin
public class JwtController {
#Autowired
private JwtService jwtService;
#PostMapping({"/authenticate"})
public JwtResponse createJwtToken(#RequestBody JwtRequest jwtRequest) throws Exception {
return jwtService.createJwtToken(jwtRequest);
}
}
service
package com.example.demo.service;
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;
import com.example.demo.dao.UserDao;
import com.example.demo.Util.JwtUtil;
import com.example.demo.entity.User;
import com.example.demo.entity.JwtResponse;
import com.example.demo.entity.JwtRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.HashSet;
import java.util.Set;
#Service
public class JwtService implements UserDetailsService {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private UserDao userDao;
#Autowired
private AuthenticationManager authenticationManager;
public JwtResponse createJwtToken(JwtRequest jwtRequest) throws Exception {
String userName = jwtRequest.getName();
String userPassword = jwtRequest.getUser_code();
authenticate(userName, userPassword);
UserDetails userDetails = loadUserByUsername(userName);
String newGeneratedToken = jwtUtil.generateToken(userDetails);
User user = userDao.findById(userName).get();
return new JwtResponse(user, newGeneratedToken);
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findById(username).get();
if (user != null) {
return new org.springframework.security.core.userdetails.User(
user.getName(),
user.getUser_code(),
getAuthority(user)
);
} else {
throw new UsernameNotFoundException("User not found with username: " + username);
}
}
private Set getAuthority(User user) {
Set<SimpleGrantedAuthority> authorities = new HashSet<>();
user.getRoles().forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
});
return authorities;
}
private void authenticate(String userName, String userPassword) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, userPassword));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED");
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS");
}
}
}
WebSecurityConfiguration
package configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#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("/authenticate", "/registerNewUser").permitAll()
.antMatchers(HttpHeaders.ALLOW).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(jwtService).passwordEncoder(passwordEncoder());
}
}
error
Description:
Field authenticationManager in com.example.demo.service.JwtService required a bean of type 'org.springframework.security.authentication.AuthenticationManager' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.security.authentication.AuthenticationManager' in your configuration.
i too had a same problem i fixed by
declaring name of the bean
#Bean(name= BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
I want to start my spring app after i made some jwt authentification configuration. but i have this issues :
Description:
Field jwtFilter in com.soheibKehal.CashApi.config.SecurityConfig required a bean of type 'filter.JwtFilter' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'filter.JwtFilter' in your configuration.
The thing is in my SecurityConfig class, i already Beaned my AuthentificationManager method, so i dont know what is the problem ?
package com.soheibKehal.CashApi.config;
import com.soheibKehal.CashApi.services.CustomUserDetailService;
import filter.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailService userDetailsService;
#Autowired
private JwtFilter jwtFilter;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/authenticate")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);;
}
}
my jwtFilter class :
package filter;
import com.soheibKehal.CashApi.Util.JwtUtil;
import com.soheibKehal.CashApi.services.CustomUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class JwtFilter extends OncePerRequestFilter {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private CustomUserDetailService service;
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException, IOException, ServletException {
String authorizationHeader = httpServletRequest.getHeader("Authorization");
String token = null;
String userName = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
token = authorizationHeader.substring(7);
userName = jwtUtil.extractUsername(token);
}
if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = service.loadUserByUsername(userName);
if (jwtUtil.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
Do you have any idea what is the problem ?
I think the problem is in your package structure. Springboot will scan your app for autoconfiguration starting from the package where you have a class of this structure
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
It should be in the package com.soheibKehal.CashApi.
The solution will be to move the filter package into the com.soheibKehal.CashApi just beside your config package.
Then spring will be able to locate the JwtFilter for autoconfiguration.
Good day developers.
I'm trying to retrieve some data for a authenticated user in my application in order to implement it in other method.This app uses Spring Security and JWT, thus the first thing to do was setting the implemetation of Java interface UserDetails on the class UserDetailsImpl as following:
package com.example.demo.services;
import com.example.demo.entiities.Renter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
import java.util.stream.Collectors;
public class UserDetailsImpl implements UserDetails {
public static final long serialVersionUID=1L;
private Long id;
private String username;
private String email;
#JsonIgnore
private String password;
private 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(Renter renter) {
List<GrantedAuthority> authorities = renter.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(renter.getRenterName()))
.collect(Collectors.toList());
return new UserDetailsImpl(
renter.getId(),
renter.getRenterName(),
renter.getRenbterEmail(),
renter.getRenterPassword(),
authorities);
}//this method would return the new user logged details accessed through the entity Renter and each
//method i need neccesary for my app comsumption , like getting the name , email, password,etc...
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
#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;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
UserDetailsImpl user = (UserDetailsImpl) o;
return Objects.equals(id, user.id);
}
}
With that implementation of the Userdetails interface , is time to also implement the UserDeailsService interface too in order to get them the UserDetails object, thus its implementation would be :
package com.example.demo.services;
import com.example.demo.entiities.Renter;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.repositories.RenterRepository;
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;
import org.springframework.transaction.annotation.Transactional;
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
RenterRepository renterRepository;
#Override
#Transactional
public UserDetails loadUserByUsername(String renterName) throws UsernameNotFoundException {
Renter renter = renterRepository.findByRenterName(renterName)
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + renterName));
return UserDetailsImpl.build(renter);
}
}
thus i get full custom Renter object using RenterRepository, then i build a UserDetails object using static build() method.
Thus next step would be setting all logic to filter the token created in every user login request,
and from there with that token generated and triggering the SecurityContextHolder i might be able to access the user authenticated details, thus:
package com.example.demo.jwt;
import com.example.demo.services.UserDetailsServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AuthTokenFilter extends OncePerRequestFilter {
#Autowired
private JwtUtils jwtUtils;
#Autowired
private UserDetailsServiceImpl userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
#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);
UserDetails userDetails = userDetailsService.loadUserByUsername(username)
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Cannot set user authentication: {}", e);
}
filterChain.doFilter(request, response);
}
Thus in this case basically inside the try statement under the condition of the generated token being valid , first i extract the user name from the token . Then from that username i got the UserDetails to create an Authentication object accessing the method of its service(loadUserByname); and after that
got settled the current UserDetails in SecurityContext using setAuthentication(authentication) method, that would be used in further implemenbtations to access the user data(didn't work)
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7, headerAuth.length());
}
return null;
}
}
Then login payload is created achieving from user interaction all data neccesary for the authetication
process on a class LoginRequest.
An the login implementation with the service and its implementation would be set in this way
RENTER SERVICE
package com.example.demo.services;
import com.example.demo.entiities.Renter;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.payload.LoginRequest;
import org.springframework.http.ResponseEntity;
import java.util.List;
import java.util.Map;
public interface RenterService {
ResponseEntity<?> loginUser(LoginRequest loginRequest)throws GeneralException;
}
RENTER SERVICE IMPLEMENTATION
package com.example.demo.services;
import com.example.demo.dto.RenterDtos;
import com.example.demo.entiities.EnumRoles;
import com.example.demo.entiities.Renter;
import com.example.demo.entiities.Role;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jsons.RenterJson;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.payload.LoginRequest;
import com.example.demo.payload.SignUprequest;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.repositories.RoleRepository;
import com.example.demo.responses.JwtResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.client.HttpServerErrorException;
import java.util.*;
import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import javax.validation.Valid;
#Service
public class RenterServiceImpl implements RenterService {
#Autowired
private RenterRepository renterRepository;
#Autowired
private RoleRepository roleRepository;
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
AuthenticationManager authenticationManager;
#Autowired
JwtUtils jwtUtils;
private static final Logger LOGGER = LoggerFactory.getLogger(RenterServiceImpl.class);
#Override
public ResponseEntity<?> loginUser(LoginRequest loginRequest) throws GeneralException {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getRenterName(), loginRequest.getRenterPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
private static List<GrantedAuthority> mapRoleUser(List<String> roles){
List<GrantedAuthority>authorities=new ArrayList<>();
for (String role : roles){
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
Then the controller with its endpoint calling all this :
package com.example.demo.controller;
import com.example.demo.dto.RenterRegisterDto;
import com.example.demo.entiities.EnumRoles;
import com.example.demo.jsons.CreateRenterJson;
import com.example.demo.jsons.RenterJson;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.payload.LoginRequest;
import com.example.demo.payload.SignUprequest;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.repositories.RoleRepository;
import com.example.demo.responses.AppResponse;
import com.example.demo.entiities.Renter;
import com.example.demo.entiities.Role;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.responses.JwtResponse;
import com.example.demo.services.RenterService;
import com.example.demo.services.UserDetailsImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/cubancoder/multirenter")
public class RegistrationController {
#Autowired
RenterService renterService;
#Autowired
AuthenticationManager authenticationManager;
#Autowired
RenterRepository renterRepository;
#Autowired
RoleRepository roleRepository;
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
JwtUtils jwtUtils;
#ResponseStatus(HttpStatus.OK)
#PostMapping(value = "/login/renter")
public AppResponse<ResponseEntity<?>> logInUser(#Valid #RequestBody LoginRequest loginRequest) throws GeneralException {
return new AppResponse<>("Success",String.valueOf(HttpStatus.CREATED),
"Ok",renterService.loginUser(loginRequest));
}
}
Until this point the user logged is achieved and all data referring to it is ok.
On a debug process i check what the implementation brings and is fine
.
THE PROBLEM STARTS HERE
Then having in mind that user logged i would like to access its data from other service implementation
in order to boost other app features, thus lets say i have a service and its implementation called ProductServiceImpl,
and in this classes i initialize methods that brings me all products, but i also want to know which user is doing that request,thus if it is logged i need all the data , otherwise the app would do other stuff.
Having in mind once the user is autheticated with token a SecurityContextHolder is already created setting the user details for that request, i guess all would be such simple as calling that SecurityContextHolder wherever i need to access the data the user logged brings right?
package com.example.demo.services;
import com.example.demo.dto.ProductDtos;
import com.example.demo.dto.RenterDtos;
import com.example.demo.entiities.*;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jwt.AuthEntryPointJwt;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.payload.LoginRequest;
import com.example.demo.repositories.ProductRepository;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.security.AuthenticationValidation;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
#Service
public class ProductServiceImpl implements ProductService {
#Autowired
ProductRepository productRepository;
#Autowired
AuthenticationManager authenticationManager;
#Autowired
UserDetailsService userDetailsService;
#Autowired
ProductDtos productDtos;
#Autowired
AuthEntryPointJwt authEntryPointJwt;
#Autowired
RenterDtos renterDtos;
#Autowired
RenterRepository renterRepository;
#Autowired
JwtUtils jwtUtils;
#Autowired
LoginRequest loginRequest;
public Map<String, Object> getAllProducts() throws GeneralException {
Map<String, Object> dto = new HashMap<>();
List<Product> listProducts = productRepository.findAll();
Option1:
Object auth = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
.....doing something here .........
Option2:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth.isAuthenticated()) {
Object Authenticated = auth.getPrincipal();
String renterLogged = ((UserDetails) Authenticated).getUsername();
.....doing something........
}
return dto;
}
}
BUT THE CONTEXT HOLDER BRINGS ME AN ANONYMOUS USER!!! not letting me proceed cause of a error saying that :
ava.lang.ClassCastException: java.lang.String cannot be cast to org.springframework.security.core.userdetails.UserDetails
at com.example.demo.services.ProductServiceImpl.getAllProducts(ProductServiceImpl.java:83) ~[classes/:na]...
And honestly i quite strayed about what else to do!.
In my debug process in order to check :
Option 1
Option 2
Last but not the least in my security package its class is set in this way :
package com.example.demo.security;
import com.example.demo.entiities.Renter;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jwt.AuthEntryPointJwt;
import com.example.demo.jwt.AuthTokenFilter;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.services.ProductServiceImpl;
import com.example.demo.services.RenterService;
import com.example.demo.services.UserDetailsImpl;
import com.example.demo.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
prePostEnabled = true)public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
RenterService renterService;
#Autowired
UserDetailsServiceImpl userDetailsService;
#Autowired
ProductServiceImpl productService;
#Autowired
private AuthEntryPointJwt unauthorizedHandler;
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/cubancoder/multirenter/**","/v2/api-docs","/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.logout().logoutUrl("/cubancoder/multirenter/logout");
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
Any help would be amazing .Please!!
My solution was:
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl currentUser = (UserDetailsImpl) authentication.getPrincipal();
This way I can access to current user in any class or method.
Regards.