Felipe A.
Felipe A.

Reputation: 949

Spring boot basic authentication

I'm using spring boot security to help me to make authentication...

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>



@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .cors().and().csrf().disable().authorizeRequests()
        .anyRequest().authenticated().and().httpBasic();
    }
}

I have a rest service to make login (on my controller) thats a post request that i send email and password and i like to use this service to make the authentication...

But i'm new on spring-boot / java... Can some one help me to make that right way?

Thanks.

Upvotes: 2

Views: 4283

Answers (3)

Mohit Sehgal
Mohit Sehgal

Reputation: 322

WebSecurityConfigurerAdaptor is deprecated now.

With Spring Security 6 and Spring boot 3, I implemented basic authentication like below:

@Configuration
@EnableWebSecurity
public class Config {
    

    @Autowired private MyBasicAuthenticationEntryPoint authenticationEntryPoint;

    @Bean
    UserDetailsService uds(PasswordEncoder pe) {
        UserDetails user1 = User.withUsername("mohit")
                .password(pe.encode("m123"))
                .authorities("USER")
                .build();
        UserDetails user2 = User.withUsername("john").password(pe.encode("m123")).authorities("USER").build();
        return new InMemoryUserDetailsManager(user1,user2);
    }
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
        .authorizeHttpRequests()
            .requestMatchers("/securityNone")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic()
            .authenticationEntryPoint(authenticationEntryPoint);
        
        //http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class);
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
}

MyAuthenticationEntryPoint looks like below:

@Component
public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void commence(
      HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) 
      throws IOException {
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() );
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 - " + authEx.getMessage());
    }

    @Override
    public void afterPropertiesSet() {
        setRealmName("MyApplication");
        super.afterPropertiesSet();
    }
}

Upvotes: 0

vikas
vikas

Reputation: 280

Change add method in SpringSecurityConfig.java like Below

    @Configuration
    @EnableWebSecurity
    public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserAuthenticationService userAuthenticationService;

    @Autowired
    private CustomAuthenticationProvider authenticationProvider;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(this.authenticationProvider).userDetailsService(this.userAuthenticationService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .cors().and().csrf().disable().authorizeRequests()
        .anyRequest().authenticated().and().httpBasic();
    }}

Create CustomAuthenticationProvider.

    @Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserAuthenticationService userAuthenticationService;

    @Override
    public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String emailId = authentication.getName();
        String password = (String) authentication.getCredentials();
        UserDetails user = this.userAuthenticationService.loadUserByUsername(emailId);
        if (user == null) {
            throw new UsernameNotFoundException("Username not found.");
        }
        //Your password encoder here
        if (!password.equals(user.getPassword())) {
            throw new UsernameNotFoundException("Wrong password.");
        }
        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
        return new UsernamePasswordAuthenticationToken(user, password, authorities);
    }}

Create Custom UserService

    @Service
public class UserAuthenticationService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmailAddressWithRole(email);
        if (user == null) {
            throw new UsernameNotFoundException("Username not found for " + email);
        }
        List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
        for (Role roles : user.getRoles()) {
            grantedAuthorities.add(new SimpleGrantedAuthority(roles.getRoleName()));
        }
        return new UserAuthenticationWrapperDto(user.getId(), user.getEmailAddress(), user.getPassword(),
                user.getUserType(), user.getCompany().getId(), grantedAuthorities,user.getName());
    }}   

Upvotes: 1

Dave Syer
Dave Syer

Reputation: 58094

You need to permit access to the login endpoint (at least). E.g.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/login", "/error").permitAll()
            .antMatchers("/**").authenticated().and().exceptionHandling()
            .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"));
}

If I were you I would remove the @EnableWebSecurity (and let Spring Boot do it's job) as well. And then in the login endpoint you need to set the security context, e.g.

@PostMapping
public void authenticate(@RequestParam Map<String, String> map,
        HttpServletRequest request, HttpServletResponse response) throws Exception {
    Authentication result = authService.authenticate(map.get("username"), map.get("password"));
    SecurityContextHolder.getContext().setAuthentication(result);
    handler.onAuthenticationSuccess(request, response, result);
}

The authService should throw BadCredentialsException if the user cannot be authenticated. Here's a sample app that I used in a blog once: https://github.com/dsyer/mustache-sample/blob/7be8459173d0b65b6d44d05f86e581d358ea9b2e/src/main/java/com/example/DemoApplication.java#L177

Upvotes: 1

Related Questions