Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticate user in spring boot with react login form

I have added spring security to my project and I am trying to do user Authentication. I am using CrudRepository to look up the user and verify the details are correct. I have been able to get it working using springs out of the box login page. My problem is that I want to authenticate the user through my react login page. The Spring boot app is at 8080 while the react app is 3000. I have seen custom login page set ups but the login page was in the same location as the spring boot app. My question is, is it possible for the login page to live elsewhere, is there a sign in end point I can send my request to to authenticate the user? Or is there some config I can add to tell spring to use the user details coming from the front end to authenticate the user.

On a side not I understand the NoOpPasswordEncoder shouldn't be used, this is just a POC and will not be going to production. Thanks

My security config file looks like below:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService)
}

@Override
protected void configure(HttpSecurity http) throws Exception {
             http
            .authorizeRequests()
            .antMatchers("/**").hasRole("ADMIN")
            .and()
            .formLogin();
}

@Bean
public PasswordEncoder getPasswordEncoder(){
    return NoOpPasswordEncoder.getInstance();
}

UserDetailsServiceImpl:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private UserRepository userRepository;

public UserDetailsServiceImpl(UserRepository userRepository) {
    this.userRepository = userRepository;
}


@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    Optional< UserEntity > user= userRepository.findByEmail(email);
    user.orElseThrow(()-> new UsernameNotFoundException("Not found: " + email));
    return user.map(UserInfo::new).get();
}

}

UserDetailsImpl

public class UserInfo implements UserDetails {
private String userName;
public UserInfo(UserEntity userEntity){
this.userName=userEntity.getEmail();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return Arrays.asList(new SimpleGrantedAuthority("ADMIN"));
}

@Override
public String getPassword() {
    return "TestPassword";
}

@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;
}

}

Spring Security Log:

Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4529048e, org.springframework.security.web.context.SecurityContextPersistenceFilter@c247b02, org.springframework.security.web.header.HeaderWriterFilter@ecfff32, org.springframework.web.filter.CorsFilter@6addfa22, org.springframework.security.web.csrf.CsrfFilter@629cf53c, org.springframework.security.web.authentication.logout.LogoutFilter@7b38db21, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@3b18009f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@78f1d29, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@15405ba1, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@74b521c, org.springframework.security.web.session.SessionManagementFilter@3c65f2e1, org.springframework.security.web.access.ExceptionTranslationFilter@531b1778, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@458704ee]

like image 203
GaB Avatar asked Oct 15 '22 04:10

GaB


1 Answers

While development you can make entry in package.json file as

"proxy": "http://localhost:8080/"

As for in java web application you can provide custom authentication request matcher and authentication entry point:

@Autowired
RestAuthEntryPoint restAuthEntryPoint;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/**").hasRole("ADMIN")
        .and()
        .exceptionHandling()
        .authenticationEntryPoint(restAuthEntryPoint) <- to support REST
        .and()
        .formLogin().loginProcessingUrl("/fooLogin"); <- credentials checked here
}

To support REST and handle unauthorized access to :

@Component
public class RestAuthEntryPoint implements AuthenticationEntryPoint{


@Override
public void commence(
        HttpServletRequest request,
        HttpServletResponse response,
        AuthenticationException authException) throws IOException {

    // send error response to the client (401 unauthorized)
    response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
}

}

Login form submission(basic) in react:

 axios({
         method:'post',
         url:'//fooLogin',
         params:{
                username: this.state.email,
                password: this.state.password
            },
         config: { headers: {'Content-Type': 'application/x-www-form-urlencoded'}}
        })
        .then(
            //authentication success...
        })
        .catch(error=>{
            var errResp = error.response;
            if(errResp.status === 401){
               //Ex: show login page again...
            }

        })
like image 185
S.Step Avatar answered Oct 20 '22 14:10

S.Step