Implementing sign in with mobile number in android and verify that in spring boot

Viewed 1124

I need help from you all in Android mobile number sign in process. I have an application, Where the user should initiate login with the mobile number then I need to verify that number using OTP based authentication in spring boot. After successful verification, JWT auth token will be generated by spring boot application and user will use that token to access other APIs.

looking forward for your replies.

Thanks

1 Answers

You need an additional authentication provider:

@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Autowired
    private OtpAuthenticationProvider otpAuthenticationProvider;

    @Autowired
    private JwtConfig jwtConfig;

    @Autowired
    private PasswordAuthenticationProvider passwordAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth
                .authenticationProvider(otpAuthenticationProvider)
                .authenticationProvider(passwordAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                // make sure we use stateless session; session won't be used to store user's state.
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // handle an authorized attempts
                .exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
                .and()
                // Add a filter to validate the tokens with every request
                .addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
                // authorization requests config
                .authorizeRequests()
                // allow all who are accessing "auth" service
                // allow /msg
                .antMatchers("/oauth/token", "/v1/auth/**").permitAll()
                // must be an admin if trying to access admin area (authentication is also required here)
                // Any other request must be authenticated
                .anyRequest().authenticated();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/webjars/**", "/swagger-ui.html**", "/favicon.ico",
                "/swagger-resources**", "/swagger-resources/**", "/csrf**", "/v2/api-docs**");
    }

    @Bean
    public JwtConfig jwtConfig() {
        return new JwtConfig();
    }

}

Here is otpAuthenticationProvider --

/**
 * @author dv singh
 */
@Component
public class OtpAuthenticationProvider implements AuthenticationProvider {

    private final AccountOtpService otpService;

    private final AccountService accountService;

    @Autowired
    public OtpAuthenticationProvider(@Lazy AccountOtpService otpService, @Lazy AccountService accountService) {
        this.otpService = otpService;
        this.accountService = accountService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        final OtpAuthenticationRequestToken request = (OtpAuthenticationRequestToken) authentication;
        AccountOtp otpPrincipal = null;
        // todo remove condition for prod, it for testing and development 
        if(!request.getToken().equals("123456")) {
            try {
                otpPrincipal = otpService.findByMobile(request.getMobile());
            } catch (NoSuchElementException e) {
                throw new BadCredentialsException("Invalid OTP");
            }
            if (!otpPrincipal.getOtp().equals(request.getToken()) || !otpPrincipal.getCreatedOn().isAfter(LocalDateTime.now()))
                throw new BadCredentialsException("Invalid OTP");
        }
        Account account;
        try {
            account = accountService.findByMobile(request.getMobile());
        } catch (NoSuchElementException e){
            account = accountService.createJobSeeker(request.getMobile(), request.getDeviceToken());
        }
        // todo remove condition for prod
        if(!request.getToken().equals("123456"))
            otpService.clearOtp(otpPrincipal);
        return new OtpAuthenticationToken(CustomAccountDetail.create(account));
    }

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