i am tryig to post an object to the database using postman , the token generated corectlly but the principal is null !? why
in the controller I have the following code .
and the error as shown
the principal tostring is : UsernamePasswordAuthenticationToken [Principal=com.accessjobs.pjp.domain.User#1a1e348b, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[]]
: the principal getName is : null
#RestController
#RequestMapping("/api/job")
#CrossOrigin //to hit the backend server when connect from the frontend server
public class JobController {
Logger logger = LoggerFactory.getLogger(JobController.class);
#Autowired
private JobService jobService;
#Autowired
private MapValidationErrorsService mapValidationErrorsService;
//#valid annotation to validate the object attributes and , i used the following code FieldErrors to display the list of errors from validation
#PostMapping("")
#CrossOrigin
public ResponseEntity<?> add(#Valid #RequestBody Job job, BindingResult result, Principal principal) {
ResponseEntity<?> errorMap = mapValidationErrorsService.MapValidationService(result);
if (errorMap != null) return errorMap;
logger.info("the principal tostring is : "+principal.toString());
logger.info("the principal getName is : "+principal.getName());
Job tempJob = jobService.add(job, principal.getName());
return new ResponseEntity<Job>(tempJob, HttpStatus.CREATED);
}
and the service job code as shown , always give me a null user and catch the error .
that because the email is null.
what is the solution>?
import com.accessjobs.pjp.domain.Job;
import com.accessjobs.pjp.domain.User;
import com.accessjobs.pjp.exceptions.JobIdException;
import com.accessjobs.pjp.repositories.JobRepository;
import com.accessjobs.pjp.repositories.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Locale;
#Service
public class JobService {
Logger logger = LoggerFactory.getLogger(JobService.class);
#Autowired
private JobRepository jobRepository;
#Autowired
private UserRepository userRepository;
public Job add(Job job,String email){
//logic , validation and handling
try {
logger.info("email .is"+email);
User user = userRepository.findByEmail(email);
logger.info("user is ::"+user.toString());
job.setUser(user);
logger.warn(user.getEmail());
job.setUserRole(user.getRole());
logger.info(user.getRole());
//convert the identifier to upper case
job.setJobIdentifier(job.getJobIdentifier().toUpperCase(Locale.ROOT));
return jobRepository.save(job);
}catch (Exception e){
throw new JobIdException("Job Identifier '"+job.getJobIdentifier().toUpperCase(Locale.ROOT)+"' already exists");
}
}
package com.accessjobs.pjp.services;
import com.accessjobs.pjp.domain.User;
import com.accessjobs.pjp.exceptions.EmailAlreadyExistsException;
import com.accessjobs.pjp.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
#Autowired //define the bean in the main spring boot app
private BCryptPasswordEncoder bCryptPasswordEncoder;//store non readable password in the database
public User register(User newUser){
try{
newUser.setPassword(bCryptPasswordEncoder.encode(newUser.getPassword()));
//user name has to be unique (exception)
newUser.setEmail(newUser.getEmail());
//make sure that pass and confpass are matches
//we dont presist or show the confirm password
newUser.setConfirmPassword("");
return userRepository.save(newUser);
}catch (Exception e){
throw new EmailAlreadyExistsException("Email' "+newUser.getEmail()+"' is already exists");
}
}
}
maybe the error in the database , how can I permit all URLs for the MySQL database
this is the class that implements the user detailsservice
package com.accessjobs.pjp.services;
import com.accessjobs.pjp.domain.User;
import com.accessjobs.pjp.repositories.UserRepository;
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 CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if(user==null) new UsernameNotFoundException("User not found");
return user;
}
#Transactional
public User loadUserById(Long id){
User user = userRepository.getById(id);
if(user==null) new UsernameNotFoundException("User not found");
return user;
}
}
is there any errors in this class ?
especially in the MySQL permissions and antMatchers?
package com.accessjobs.pjp.security;
import com.accessjobs.pjp.services.CustomUserDetailsService;
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.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.web.authentication.UsernamePasswordAuthenticationFilter;
import static com.accessjobs.pjp.security.SecurityConstants.*;
//video rep branch 65
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(customUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
#Bean(BeanIds.AUTHENTICATION_MANAGER)
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// .and().headers().frameOptions().sameOrigin() //To enable H2 Database
.and()
.authorizeRequests()
.antMatchers(
"/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).permitAll()
.antMatchers("/api/users/**").permitAll()
.antMatchers(SIGN_UP_URLS).permitAll()
.antMatchers("jdbc:mysql://localhost:3306/").permitAll()**//here ?**
.antMatchers("/api/users/**").permitAll()
.antMatchers("/api/users/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
Make sure your token has a sub property. Use this tool to post the contents of your token (minus any secure properties).
https://jwt.io/
Related
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();
}
}
I'm trying to configure Spring Security on a Spring Boot application as follows and as a result Postman gives 401 Unauthorized ,please can anyone help me to solve this error
controller
package com.example.demo.controller;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
#CrossOrigin(origins = "http://localhost:8080")
#RestController
#RequestMapping("/api")
public class UserController {
#Autowired
private UserService userService;
#PostConstruct
public void initRoleAndUser() {
userService.initRoleAndUser();
}
#PostMapping({"/registerNewUser"})
public User registerNewUser(#RequestBody User user) {
return userService.registerNewUser(user);
}
#GetMapping({"/forAdmin"})
#PreAuthorize("hasRole('Admin')")
public String forAdmin(){
return "This URL is only accessible to the admin";
}
#GetMapping({"/forUser"})
#PreAuthorize("hasRole('User')")
public String forUser(){
return "This URL is only accessible to the user";
}
}
configuration
package configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
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;
#Override
#Bean
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());
}
}
JwtService
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.context.annotation.Bean;
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;
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");
}
}
}
I use postman to test and when I do a GET to "http://localhost:8080/forAdmin", I get an error 401 Unauthorized
You must load the user into memory from the database, and it should be converted to UserDetails. The user details has Roles, or Authorities. It dependes what you choose. Maybe these articles can help :)
https://www.baeldung.com/spring-security-authentication-with-a-database
https://www.baeldung.com/role-and-privilege-for-spring-security-registration
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 am configuring spring security in my project using jwt token.
I am sucessfully generated jwt token and accessing it from front end.
In my spring boot REST APT I have several controllers with all CRUD methods.
I want to give access of get method to all the users and even to public, while
for POST,PUT and Delete I want to give access to only admin and moderator depending on the case.
But for some POST method like in inquiry form i want to give access to all users.
What approach should I follow for that,
Do i need to write
#PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
for each method in each controller.
Right now i just build a test page to check access of roles .
package com.panchmeru_studio.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/api/test")
public class TestController {
#GetMapping("/all")
public String allAccess() {
return "Public Content.";
}
#GetMapping("/user")
#PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
public String userAccess() {
return "User Content.";
}
#GetMapping("/mod")
#PreAuthorize("hasRole('MODERATOR')")
public String moderatorAccess() {
return "Moderator Board.";
}
#GetMapping("/admin")
#PreAuthorize("hasRole('ADMIN')")
public String adminAccess() {
return "Admin Board.";
}
}
Securityconfig.java
package com.panchmeru_studio.security.jwt;
import com.panchmeru_studio.filter.AuthTokenFilter;
import com.panchmeru_studio.security.service.ApplicationUserDetailsService;
import com.panchmeru_studio.security.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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;
import org.springframework.security.web.server.authorization.AuthorizationWebFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import static com.panchmeru_studio.constants.SecurityConstants.SIGN_UP_URL;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private MyUserDetailsService userDetailsService;
// private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private AuthEntryPointJwt unauthorizedHandler;
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
public SecurityConfiguration(MyUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
// this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated().and()
// .addFilter(new AuthenticationFilter(authenticationManager()))
// .addFilter(new AuthorizationFilter(authenticationManager()))
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler);
// .authorizeRequests().antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
// .anyRequest().authenticated()
// .and()
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Now for example i have 10 controllers, Project ,AboutUS , ProjectCategory,Gallery
Each has different url(Request mapping) so, Do i need to assign #PreAuthorize to each method to each controller and then give request mapping of each controller to security config to give authrization?
If you want to base the access to methods only on user roles, then the approach you described is the correct one.
Since you're using JWTs to authorize access to your APIs, you could secure the APIs based on claims in JWTs instead of the user profile. In such a setup you don't need access to user accounts at all, you make all the decisions based on what is in the JWT. Have a look at this example to see how to set this up in a Spring API.