Home > Net >  Opaque Token Implementation in spring security
Opaque Token Implementation in spring security

Time:09-22

im trying to create a secured spring rest api for the security i want to use opaque token stored in the database so that if the client query on the api with a bearer token . the server will check on the database if the token exist if the token is valid and get the user and the privilege and check if the user have the authority to do the request. i've done some research on the net but didn't found result that can be understood by a beginner. how can i implement this. method 1 found method 2 i have found this two methods but i dont know where too implements the database verification and validation

CodePudding user response:

after a lot of research i've found this and it is working first i've created a Authorization filter like this :

package com.example.bda_test_11.security;

import com.example.bda_test_11.model.BdaUser;
import com.example.bda_test_11.model.Token;
import com.example.bda_test_11.repository.TokenRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class AuthorizationFilter extends BasicAuthenticationFilter {
    private final TokenRepository tokenRepository;
    public AuthorizationFilter(AuthenticationManager authenticationManager,TokenRepository tokenRepository) {
        super(authenticationManager);
        this.tokenRepository = tokenRepository;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String tokenCode = request.getHeader(HttpHeaders.AUTHORIZATION);
        log.info(tokenCode);
        if(tokenCode == null ) {
            filterChain.doFilter(request,response);
            return;
        }
        Token token = tokenRepository.findByCode(tokenCode).orElse(null);
        if (token == null) {
            
            filterChain.doFilter(request,response);
            return;
        }
        BdaUser user = token.getUser();
        UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken(user.getLogin(),null,user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(userToken);
        filterChain.doFilter(request,response);
    }
}

and a UsernamePasswordAuthenticationFilter like this

package com.example.bda_test_11.security;

import com.example.bda_test_11.security.domain.LoginCredentials;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@Slf4j
public class JsonObjectAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final ObjectMapper objectMapper = new ObjectMapper();



    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        try{


            BufferedReader reader = request.getReader();
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line=reader.readLine())!=null){
                stringBuilder.append(line);
            }
            LoginCredentials authRequest = objectMapper.readValue(stringBuilder.toString(),LoginCredentials.class);
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                    authRequest.getLogin(),
                    authRequest.getPassword()
            );
            setDetails(request,token);
            log.info(token.toString());
            return this.getAuthenticationManager().authenticate(token);
        } catch (IOException e){
            throw new RuntimeException(e);
        }
    }
}

if the connection is successful we generate a token like :

package com.example.bda_test_11.security;

import com.example.bda_test_11.model.BdaUser;
import com.example.bda_test_11.model.Token;
import com.example.bda_test_11.repository.TokenRepository;
import com.example.bda_test_11.service.BdaUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j @Component
public class AuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    private final TokenRepository tokenRepository;
    private final BdaUserService userService;

    @Autowired
    public AuthSuccessHandler(TokenRepository tokenRepository, BdaUserService userService) {
        this.tokenRepository = tokenRepository;
        this.userService = userService;
    }
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        BdaUser user = userService.findByLogin(principal.getUsername());
        Token token = new Token(user);
        tokenRepository.save(token);
        log.info(token.getCode());
        response.addHeader("Authorization",token.getCode());
        response.addHeader("Content-Type","application/json");
        response.getWriter().write("{\"token\":" token.getCode() ",\"login\":" user.getLogin());
    }
}

and then ive configured the filterChain bean like this

package com.example.bda_test_11.security;

import com.example.bda_test_11.repository.TokenRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;

@Configuration
public class BdaSecurity {
    private final AuthenticationManager authenticationManager;
    private final AuthSuccessHandler authSuccessHandler;
    private final TokenRepository tokenRepository;

    @Autowired
    public BdaSecurity(AuthenticationManager authenticationManager, AuthSuccessHandler authSuccessHandler, TokenRepository tokenRepository) {
        this.authenticationManager = authenticationManager;
        this.authSuccessHandler = authSuccessHandler;
        this.tokenRepository = tokenRepository;
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .authorizeHttpRequests((auth)->{

                    try {
                        auth
                                .antMatchers("/api/admin").hasAuthority("ADMIN")
                                .antMatchers("/api/user").hasAuthority("USER")
                                .anyRequest().permitAll()
                                .and()
                                .sessionManagement()
                                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                                .and()
                                .addFilter(authenticationFilter())
                                .addFilter(new AuthorizationFilter(authenticationManager,tokenRepository))
                                .exceptionHandling()
                                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                })
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }
    @Bean
    public JsonObjectAuthenticationFilter authenticationFilter() {
        JsonObjectAuthenticationFilter filter = new JsonObjectAuthenticationFilter();
        filter.setAuthenticationSuccessHandler(authSuccessHandler);
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }
}
  • Related