I am trying to learn Spring security using JWT method. While doing this there is no error in program, but I am not getting token on my Postman client.
Here is my code:
( here I am not dealing with any database, so created fake username and password )
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
if(userName.equals("foo"))
return new User("foo", "foo" , new ArrayList<>());
else
throw new UsernameNotFoundException("User Not Found");
}
}
(Controller code )
public class JwtController {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtUtil jwtutil;
#RequestMapping(value = "/token" , method = RequestMethod.POST)
public ResponseEntity<?> generateToken(#RequestBody JwtRequest jwtRequest ) throws Exception
{
System.out.println(jwtRequest);
try
{
this.authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(jwtRequest.getUsername()
, jwtRequest.getPassword()));
}
catch(UsernameNotFoundException e)
{
e.printStackTrace();
throw new Exception("Bad Credentials");
}
UserDetails userDetails = this.customUserDetailsService.loadUserByUsername(jwtRequest.getUsername());
String token = this.jwtutil.generateToken(userDetails);
System.out.println("JWT Token "+ token);
// Now we want to send this token back to client
return ResponseEntity.ok(new JwtResponse(token));
}
}
(Configuration code )
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable().authorizeRequests().antMatchers("/token")
.permitAll().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder()
{
return NoOpPasswordEncoder.getInstance();
}
}
(Jwt Request and response )
public class JwtRequest {
private String username;
private String password;
// getters and setters and constructors
}
public class JwtResponse {
String token;
// getters and setters and constructors
}
Jwtutil class code I have copied from
JwtUtil.java
Postman request
{
"username": "foo",
"password": "foo"
}
Postman response
{
"timestamp": "2021-03-20T05:21:01.251+00:00",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/token"
}
Where am I wrong ? Could anyone help me ?
You have to add #RestController to your JwtController class to make it available :)
Related
I am having some issue on my Spring security sign-in. Signup works fine with no error but only sign-in returns 403 forbidden error.
I tried add http.httpBasic() and it returns 401 error.
I have http.csrf().disable() in the SecurityConfig.java but it still doesn't work even it's permitAll() condition. I am stuck in this problem for days :/ I tried every single solution that I googled but nothing worked.
Here is SecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();//cross-origin-resource-sharing
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers("/api/authentication/**").permitAll()//login and register pre-path
.anyRequest().permitAll();
http.addFilterBefore(jwtAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public JwtAuthorizationFilter jwtAuthorizationFilter()
{
return new JwtAuthorizationFilter();
}
#Override
#Bean(BeanIds.AUTHENTICATION_MANAGER)
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Bean
public WebMvcConfigurer corsConfigurer()
{
return new WebMvcConfigurer()
{
#Override
public void addCorsMappings(CorsRegistry registry)
{
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
}
};
}
I think from this jwtAutheorizationFiler.java cause the issue if the Security config is fine:
public class JwtAuthorizationFilter extends OncePerRequestFilter
{
#Autowired
private JwtProvider jwtProvider;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{
Authentication authentication = jwtProvider.getAuthentication(request);
if (authentication != null && jwtProvider.isTokenValid(request))
{
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
SecurityUtils.java
public class SecurityUtils
{
public static final String ROLE_PREFIX = "ROLE_";
public static final String AUTH_HEADER = "authorization";
public static final String AUTH_TOKEN_HEADER = "Bearer";
public static final String AUTH_TOKEN_PREFIX = AUTH_TOKEN_HEADER + " ";
public static SimpleGrantedAuthority convertToAuthority(String role)
{
String formattedRole = role.startsWith(ROLE_PREFIX) ? role : ROLE_PREFIX + role;
return new SimpleGrantedAuthority(formattedRole);
}
public static String extractAuthTokenFromRequest(HttpServletRequest request)
{
String bearerToken = request.getHeader(AUTH_HEADER);
if(StringUtils.hasLength(bearerToken) && bearerToken.startsWith(AUTH_TOKEN_PREFIX))
{
return bearerToken.substring(7);
}
return null;
}
}
CustomUserDetailService.java :
#Service
public class CustomUserDetailsService implements UserDetailsService
{
private LoginService loginService;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
Login login = loginService.findByUsername(username)
.orElseThrow(()-> new UsernameNotFoundException("User not found with username: "+ username));
Set<GrantedAuthority> authorities = Set.of(SecurityUtils.convertToAuthority(login.getRole().name()));
return UserPrincipal.builder()
.login(login)
.id(login.getId())
.username(login.getUsername())
.password(login.getPassword())
.authorities(authorities)
.build();
}
}
AuthenticationController.java
#Autowired
private AuthenticationService authenticationService;
#Autowired
private LoginService loginService;
#Autowired
private JwtRefreshTokenService jwtRefreshTokenService;
#PostMapping("sign-up")//api/authentication/sign-up
public ResponseEntity<?> signUp(#RequestBody Login login)
{
if(loginService.findByUsername(login.getUsername()).isPresent())
{
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
return new ResponseEntity<>(loginService.saveLogin(login), HttpStatus.CREATED);
}
#PostMapping("sign-in")//api/authentication/sign-in
public ResponseEntity<?> signIn(#RequestBody Login login)
{
return new ResponseEntity<>(authenticationService.signInAndReturnJWT(login), HttpStatus.OK);
}
AuthenticationServiceImple.java
#Service
public class AuthenticationServiceImpl implements AuthenticationService
{
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtProvider jwtProvider;
#Autowired
private JwtRefreshTokenService jwtRefreshTokenService;
#Override
public Login signInAndReturnJWT(Login signInRequest)
{
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(signInRequest.getUsername(), signInRequest.getPassword())
);
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
String jwt = jwtProvider.generateToken(userPrincipal);
Login signInUser = userPrincipal.getLogin();
signInUser.setAccessToken(jwt);
signInUser.setRefreshToken(jwtRefreshTokenService.createRefreshToken(signInUser.getId()).getTokenId());
return signInUser;
}
}
I am new to spring boot and spring security and not able to understand the following error on my own.
my spring boot application simply contains two URLs one which is accessed by anyone i.e, only by whose name password is saved in database and another which can only ADMIN can access(to add user and there roll in MySql database).
But when i am passing username and password it saying:-
org.springframework.security.authentication.InternalAuthenticationServiceException: UserDetailsService returned null, which is an interface contract violation
I am posting all necessary class below:-
CustomUserDetailService:-
#Service
public class CustomUserDetailService implements UserDetailsService {
#Autowired
private UserRepository repository;
#Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
User user= repository.findByname(name);
CustomUserDetail userDetail=null;
if(user!=null){
CustomUserDetail userDetails=new CustomUserDetail();
userDetails.setUser(user);
}else{
throw new UsernameNotFoundException("User not exist with name :" +name);
}
return null;
}
}
CustomUserDetail
public class CustomUserDetail implements UserDetails {
private User user;
/*Getter and Setter*/
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
/*Overriden methods from userDetail*/
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getRoles().stream().map(role -> new SimpleGrantedAuthority("Role_"+role))
.collect(Collectors.toList());
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getName();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
BasicConfig:-
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class BasicConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(encodePWD());
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/user/").permitAll()
.and()
.authorizeRequests()
.antMatchers("/MiniApi/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
}
#Bean
public BCryptPasswordEncoder encodePWD()
{
return new BCryptPasswordEncoder();
}
}
Controller Classes:-
I am not making two #Restcontroller classes and only single #RequestMapping() is acting as base URL
AdminController:-
#RestController
#RequestMapping("/MiniApi")
public class Admincontroller
{
#Autowired
private UserRepository userRepository;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#PreAuthorize("hasAnyRole('ADMIN')")
#PostMapping("/admin/add")
public String addUser(#RequestBody User user)
{
String pwd = user.getPassword();
String encryptPwd = passwordEncoder.encode(pwd);
user.setPassword(encryptPwd);
userRepository.save(user);
return "User added successfully...";
}
}
AnyOne:-
public class AnyOne {
#GetMapping("/anyone")
public String Anyone()
{
return "processing......";
}
}
Change what i made:-
If i am removing return statement from CustomUserDetailService i am getting return statement missing error and then i added return userDetails;
it gives me :-
First it askes me for username and password i provided it and then this
HTTP Status 403 – Forbidden
You are returning null instead of userDetails
#Service
public class CustomUserDetailService implements UserDetailsService {
#Autowired
private UserRepository repository;
#Override
public UserDetails loadUserByUsername(String name) throws
UsernameNotFoundException {
User user= repository.findByname(name);
CustomUserDetail userDetail=null;
if(user != null){
CustomUserDetail userDetails=new CustomUserDetail();
userDetails.setUser(user);
return userDetails;
}
throw new
UsernameNotFoundException("User not exist with name :" +name);
}
}
Hey everyone i have problem with jwt with Java.Here is the codes.
Here is returned value from postman
{
"timestamp": "2020-02-29T20:53:35.761+0000",
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/login"
}
TokenManager.java
#Service
public class TokenManager {
private static final int expiredAt = 10 * 60 * 60 * 1000;
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public String generateToken(String username){
return Jwts.builder().setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiredAt))
.signWith(key).compact();
}
public boolean tokenValidate(String token){
if(getUserFromToken(token) != null && isExpired(token)) {
return true;
}
return false;
}
public String getUserFromToken(String token){
Claims claims = getClaims(token);
return claims.getSubject();
}
public boolean isExpired(String token){
Claims claims = getClaims(token);
return claims.getExpiration().after(new Date(System.currentTimeMillis()));
}
private Claims getClaims(String token) {
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
}
}
And then JwtTokenFilter.java
#Component
public class JwtTokenFilter extends OncePerRequestFilter {
#Autowired
private TokenManager tokenManager;
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
#NotNull HttpServletResponse httpServletResponse,
#NotNull FilterChain filterChain) throws ServletException, IOException {
final String authHeader = httpServletRequest.getHeader("Authorization");
String username = null;
String token = null;
if (authHeader != null && authHeader.contains("Bearer")) {
token = authHeader.substring(7);
try {
username = tokenManager.getUserFromToken(token);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
if (username != null && token != null
&& SecurityContextHolder.getContext().getAuthentication() == null) {
if (tokenManager.tokenValidate(token)) {
UsernamePasswordAuthenticationToken upassToken =
new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
upassToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(upassToken);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
And my custom UserDetailService
#Service
public class CustomUserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
Here is WebSecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtTokenFilter tokenFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/signup","/login").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public AuthenticationManager getAuthenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
And last one is my controller.I checked the request body and and print the data it just work fine but /login path returns access denied.
#RestController
public class UserController {
#Autowired
private UserService userService;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private TokenManager tokenManager;
public UserController(UserService userService, AuthenticationManager authenticationManager, TokenManager tokenManager) {
this.userService = userService;
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
}
#RequestMapping(value = "/signup", method = RequestMethod.POST)
public ResponseEntity<User> signup(#RequestBody User user){
return ResponseEntity.ok(userService.save(user));
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<String> login(#Valid #RequestBody AuthRequest authRequest){
try{
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(),authRequest.getPassword()));
return ResponseEntity.ok(tokenManager.generateToken(authRequest.getUsername()));
}catch (Exception e){
throw e;
}
}
}
When I remove authenticationManager.authenticate method inside login function it returns a valid token.But when I add authenticationManager again it returns access denied.
Actually you did not setup the AuthenticationManager properly.
in your code, you just used the default authentication manager. And it is ok, as there is one default implementation shipped in Spring boot security, which is ProviderManager. what [ProviderManager][1] does is:
Iterates an Authentication request through a list of AuthenticationProviders.
So you need at least one AuthenticationProvider
There are quite some AuthenticationProviders, for example:
AnonymousAuthenticationProvider, NullAuthenticationProvider, DaoAuthenticationProvider, LdapAuthenticationProvider etc
And in your case, you are authenticating against database, so the DaoAuthenticationProvider is the choice.
And Spring security has a very easy way to configure the DaoAuthenticationProvider, and actually, it automatically created one for you when you set userDetailsService to the AuthenticationManagerBuilder to configure your AuthenticationManager, code like this:
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
so all you need to do is add the code snipet above to your WebSecurityConfig
And it is also recommended to use PasswordEncoder instead of storing your password as plain text. A simple way is to use BCryptPasswordEncoder to encode your password before save the user to db...
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
Hello Everyone i'm new in spring security and jwt. I'm implementing Jwt in my spring boot project to secure user login and i'm using spring boot 2.1.5
and i don't know much about new bean restriction in spring boot 2+ .
I need some help .. here i'm trying to #Autowired UserDetailsService and code run fine ..and result is also fine.. but intellij shows error at
#Autowired UserDetailsService jwtUserDetailsService
saying ... Could not autowire. There is more than one bean of UserDetailsService type.
Can anyone explain me what what happens wrong here why i can't autowired and why and what are the Autowired restriction in spring boot 2+ ?
And thanks in advance
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private JwtFilter jwtFilter;
#Autowired
private UserDetailsService jwtUserDetailsService; // here i got error only
#Autowired
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).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.csrf().disable();
http.authorizeRequests().antMatchers("/api/user/add", "/generate").permitAll().anyRequest().authenticated().and() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
}
my customUserDetailService is
#Service
public class JwtUserDetailService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user != null) {
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username does't exists");
}
}
}
My JwtController class which expose restend point to generate jwt token
#CrossOrigin
#RestController
public class JwtController {
#Autowired
private JwtUtils jwtUtils;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtUserDetailService jwtUserDetailService;
#PostMapping(value = "/generate")
public ResponseEntity<?> generateToken(#RequestBody JwtRequest jwtRequest) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(jwtRequest.getUsername(),
jwtRequest.getPassword()));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVAILD_CREDENTIALS", e);
}
final UserDetails userDetails = jwtUserDetailService.loadUserByUsername(jwtRequest.getUsername());
final String token = jwtUtils.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
}
My JwtFilter Class
#Component
public class JwtFilter extends OncePerRequestFilter {
#Autowired
private JwtUserDetailService jwtUserDetailService;
#Autowired
private JwtUtils jwtUtils;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtUtils.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.jwtUserDetailService.loadUserByUsername(username);
if (jwtUtils.validate(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Other thing as just normal like entity, repository, and some secured restend points
UserDetailsService was provided by spring.
To Autowire you need to configure it with.
#Bean
public UserDetailsService getUserDetails(){
return new JwtUserDetailService(); // Implementation class
}
If you are not interested in Bean Configuration.
you can autowire JwtUserDetailService directly.
#Autowired
private JwtUserDetailService jwtUserDetailsService;
I got the same error in another context. The reason was the Idea don´t know which bean of type 'UserDetailsService' to use.
My solution is through annotation Qualifier:
#Qualifier("beanNameWhichYouWantUse")
#Autowired
private UserDetailsService jwtUserDetailsService;
If use Idea: give mouse point on the error, select from context menu:
"More actions" -> "Add qualifier"
and finally select the bean
You can put this code in application.properties:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
I am using spring-boot and spring-security in app. My goal is to get the user name of the currently registered user from post method. Get method is working nicely but the post method isn't working. Why? How can I solve this problem?
Test Controller
#GetMapping("/test")
public String test(Authentication authentication) {
System.out.println(authentication.getName()); // <--------- It's working
return "testfile";
}
#PostMapping("/test")
public String testPost(Authentication authentication) {
System.out.println(authentication.getName()); // <--------- NOLL ERROR!
return "testfile";
}
Error
java.lang.NullPointerException: null
User
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private long id;
#Column(name="mail")
private String mail;
#Column(name="password")
private String password;
}
UserDAO
#Repository
public class UserDAO {
#Autowired
private EntityManager entityManager;
public List<User> findAll() {
return entityManager.unwrap(Session.class).createQuery("from User", User.class).getResultList();
}
public User findByMail(String mail){
Session currentSession = entityManager.unwrap(Session.class);
Query theQuery = currentSession.createQuery("from User where mail=:mail", User.class);
theQuery.setParameter("mail", mail);
List<User> users = theQuery.getResultList();
if(users.isEmpty()){
return new User();
}
return users.get(0);
}
public void saveOrUpdate(User user) {
Session currentSession = entityManager.unwrap(Session.class);
currentSession.saveOrUpdate(user);
}
}
UserService
public interface UserService extends UserDetailsService{
public List<User> findAll();
public User findByMail(String mail);
public void saveOrUpdate(User user);
}
UserServiceImpl
#Service
public class UserServiceImpl implements UserService{
#Autowired
private UserDAO userDAO;
#Autowired
private UserRoleDAO userRoleDAO;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
#Transactional
public List<User> findAll() {
return userDAO.findAll();
}
#Override
#Transactional
public User findByMail(String mail){
return userDAO.findByMail(mail);
}
#Override
#Transactional
public void saveOrUpdate(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userDAO.saveOrUpdate(user);
}
#Override
#Transactional
public UserDetails loadUserByUsername(String mail) throws UsernameNotFoundException {
User user = userDAO.findByMail(mail);
List<UserRole> userRole = userRoleDAO.findByUserId(user.getId());
if (user == null) {
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), mapRolesToAuthorities(userRole));
}
private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<UserRole> roles) {
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getRole())).collect(Collectors.toList());
}
}
SecurityConfig
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private Environment env;
#Autowired
private DataSource dataSource;
#Autowired
private UserService userService;
RedirectAuthenticationSuccessHandler redirectAuthenticationSuccessHandler = new RedirectAuthenticationSuccessHandler();
RedirectAuthenticationFailureHandler redirectAuthenticationFailureHandler = new RedirectAuthenticationFailureHandler();
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery(env.getProperty("my.usersbyusernamequery"))
.authoritiesByUsernameQuery(env.getProperty("my.authoritiesbyusernamequery"));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/anypage1/**").hasRole("MANAGER")
.antMatchers("/anypage2/**").hasRole("ADMIN")
.antMatchers("/test").hasRole("ADMIN")
.authenticated()
.antMatchers("/**").permitAll()
.and()
.formLogin().loginPage("/login").failureHandler(redirectAuthenticationFailureHandler)
.loginProcessingUrl("/login-control").successHandler(redirectAuthenticationSuccessHandler).permitAll()
.and()
.logout().logoutUrl("/logout").permitAll().and().exceptionHandling().accessDeniedPage("/access-denied");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.POST, "/anypage3").antMatchers(HttpMethod.POST, "/anypage4")
.antMatchers(HttpMethod.POST, "/test");
}
#Bean
public BCryptPasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.POST, "/anypage3").antMatchers(HttpMethod.POST, "/anypage4")
.antMatchers(HttpMethod.POST, "/test");
}
You ignore /test in post method, so it will not be filtered by spring security filter, try to remove this.
You can get username from SecurityContextHolder
User user =
(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername(); //get current logged in username
In loadUserByUsername method you can manually set the Authentication token on SecurityContextHolder and same you can use in controller
UsernamePasswordWithAttributesAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loadUserByUsername(username), password, authorities );
SecurityContextHolder.getContext().setAuthentication(authenticationToken);