Secure REST API calls - mumayank/Rest-Api-Documentation GitHub Wiki

pom.xml file

Add in dependencies tag:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.0</version>
</dependency>

Add in application.properties file:

tokenSecret=QWEDSaskdf842#$%

Constants file

class Constants {

    companion object {

        private val oneSecond = 1000.toLong()
        private val oneMinute = 60 * oneSecond
        private val oneHour = 60 * oneMinute
        private val oneDay = 24 * oneHour
        private val oneWeek = 7 * oneDay
        private val oneMonth = 30 * oneDay

        val expiryTime = oneWeek
        val tokenPrefix = "Bearer "
        val headerString = "Authorization"
        val signUpUrl = "/users"

        fun getTokenSecret(applicationContext: ApplicationContext): String {
            return applicationContext.environment.getProperty("tokenSecret") ?: ""
        }
    }
}

Create login POJO class

public class UserSignIn {
    private String email;
    private String password;
    // getters/ setters
}

Add in Application class:

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

Create WebSecurity class

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    UserRepository userRepository;

    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public WebSecurity(BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, Constants.Companion.getSignUpUrl()).permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(getAuthenticationFilter())
                .addFilter(new BasicAuthenticationFilter(authenticationManager()) {
                    @Override
                    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
                        String header = request.getHeader(Constants.Companion.getHeaderString());
                        if (header == null || header.startsWith(Constants.Companion.getTokenPrefix()) == false) {
                            SecurityContextHolder.getContext().setAuthentication(null);
                            chain.doFilter(request, response);
                            return;
                        }

                        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = getAuthentication(request);
                        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                        chain.doFilter(request, response);
                    }
                })
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(email -> {
            UserEntity userEntity = userRepository.findByEmail(email);
            if (userEntity == null) {
                throw new UsernameNotFoundException(email);
            } else {
                return new User(userEntity.getEmail(), userEntity.getPassword(), new ArrayList<>());
            }
        }).passwordEncoder(bCryptPasswordEncoder);
    }

    private UsernamePasswordAuthenticationFilter getAuthenticationFilter() {
        UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter() {
            @Override
            public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
                try {
                    UserSignIn userSignIn = new ObjectMapper().readValue(request.getInputStream(), UserSignIn.class);
                    return authenticationManager().authenticate(new UsernamePasswordAuthenticationToken(
                            userSignIn.getEmail(),
                            userSignIn.getPassword(),
                            new ArrayList<>()
                    ));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            @Override
            protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
                String username = ((User) authResult.getPrincipal()).getUsername();
                String token = Jwts.builder()
                        .setSubject(username)
                        .setExpiration(new Date(System.currentTimeMillis() + Constants.Companion.getExpiryTime()))
                        .signWith(SignatureAlgorithm.HS512, Constants.Companion.getTokenSecret(getApplicationContext()))
                        .compact();

                response.addHeader(Constants.Companion.getHeaderString(), Constants.Companion.getTokenPrefix() + token);
            }
        };

        usernamePasswordAuthenticationFilter.setFilterProcessesUrl("/users/login");
        return usernamePasswordAuthenticationFilter;
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader(Constants.Companion.getHeaderString());
        if (token != null) {
            token = token.replace(Constants.Companion.getTokenPrefix(), "");
            String user = Jwts.parser()
                    .setSigningKey(Constants.Companion.getTokenSecret(getApplicationContext()))
                    .parseClaimsJws(token)
                    .getBody()
                    .getSubject();
            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }
}

Encypt passwords

Always store encrypted passwords in DB:

userEntity.password = bCryptPasswordEncoder.encode(userEntity.password)
⚠️ **GitHub.com Fallback** ⚠️