Approve or refuse a request through Handlerinterceptoradapter

Asked

Viewed 791 times

13

It is known that all requisitions by @RequestMapping are "public", where any user can access them through the browser.

The question is, how to approve Requests where only the system can request and refuse such a request if it is already accessed by the user directly in the browser.

I’m currently validating a key coming from Request Header, however there are plugins that can change the header, "shitting" with all logic.

For better understanding, I am using the following code to verify the key, where the request has the key that I’m comparing, it lets the request run, otherwise it blocks.

@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object controller) throws Exception {

    String Accept = request.getHeader("Authority");

    if(Accept != null && Accept.equalsIgnoreCase("KeyDefinida")){
        return true;    
    }
    return false;
}

Called ajax

$.ajax
({
   url: "",
   headers: {          
     "Authority" : "KeyDefinida"
   },
  • 1

    Hi Matheus, if you really need authentication / authorization I would take a look at Spring Security, creating a single user for the system. But this kind of problem back and forth can be solved in another layer. E.g., system services may be hidden from the end user (system topology).

  • 1

    @Matheus Have you considered the possibility of using token?

  • @Type where I pass the header?

  • @Matheus Yes, but you would use a library to do this. In my case I use JWT, but as mentioned above you can use Spring Security

  • @Diegoaugusto I will take a look at this library. Vlw.

2 answers

4


Good morning, the most viable, reliable and appropriate solution in your case I believe would be to work with the spring-security:

pom

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>

To enable spring-secutiry you will need the annotation @EnableWebSecurity You will need to configure users to within the spring context, you can configure them inMemory if using only some entry points restriction for the system, or fixed users:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
    auth.inMemoryAuthentication()
        //Caso o usuario de sistema pode ser tbm adm, mais se preferir pode deixar apenas System
        .withUser("UsuarioSistema").password("SenhaUsuarioSistema").roles("SYSTEM", "ADMIN").and()
        //Não é obrigatório
        .withUser("usuario1").password("senha1").roles("USER");
}

Or work with an implementation of UserDetailsService

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

To work with the UserDetailsService follows an example with jpa (but you can work with any database):

Your user table

@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String username;
    private String password;
    @ManyToMany
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;

    //Gets e Sets
}

Your Permissions table

@Entity
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @ManyToMany(mappedBy = "roles")
    private Set<User> users;

    //Gets e Sets
}

Repository interface for the user

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

Repository interface for permissions

public interface RoleRepository extends JpaRepository<Role, Long>{
}

Implementation of the Userdetailsservice

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

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);

        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
        for (Role role : user.getRoles()) {
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
                grantedAuthorities);
    }
}

Finally the last step, you will need to configure the security standards you will use, basically it allows you to make various settings, I will leave an example of configuration using X509 (private and public key)protection against attack xss and disabling the csrf action token (validation of actions allowed to the user). spring-security exists a universe of settings that you can use or customize, suggested links spring Docs, algaworks and devmedia

General configuration of spring-security

//Classe de configuração geral do spring-security
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    //Padrões de configuração de seu sistema
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //Autorização para requisições
        http.authorizeRequests()
            //Permite acesso de todos para / para frente
            .antMatchers("/**")
                .permitAll().and()
            //Permite acesso apenas de usuarios System para /meuEndPoint/ para frente
            .antMatcher("/meuEndPoint/**")
                .authorizeRequests()
                .anyRequest().hasRole("SYSTEM")
            .anyRequest().authenticated()
            .and().httpBasic();

        //Configurações
        http.x509().and()
            .headers().xssProtection().and().and()
            .csrf().disable();
    }

}

Still within the settings SecurityConfiguration, if you used the UserDetailsService will need to inject the implementation of UserDetailsService and implement the method configureGlobal in this way:

Settings Userdetailsservice

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

if you have used the inMemory user you will need to implement the configureGlobal in this way:

Configuration inMemory

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        auth.inMemoryAuthentication()
            .withUser("UsuarioSistema").password("SenhaUsuarioSistema").roles("SYSTEM", "ADMIN").and()
            .withUser("usuario1").password("senha1").roles("USER");
    }

Another important point, if you want to use some kind of encryption (highly recommended), need to inject the BCryptPasswordEncoder:

Cryptography

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

also change the settings to

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}

remembering that with the encryption enabled you must save in the bank or inMemory the password of already encrypted users.

  • Excellent answer.

0

You can use the header "User-Agent".

This header provides information where the user comes from.

Follow an example of User-Agent:

User-Agent: Mozilla/5.0 (X11; Linux x86_64) Applewebkit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36

You can test with the browsers you want to support and just accept these headers.

I hope I’ve helped,

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object controller) throws Exception {

    String accept = request.getHeader("User-Agent"); //Deixei o nome da variável em CamelCase por padrão.

    if(accept != null && accept.contains("Mozilla")) {
        return true;    
    }
    return false;
}
  • I think it is not caring with the browser that makes the request, but the user itself...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.