Monday, June 26, 2023

Spring Security - Step3 - Sample Spring Security application - add authorization

Previously once you authenticated with credentials, both "/all" and "{id}" urls were exposed to both users.

One is Admin and other oner is with USER privileges.

Now let's see handle authorization.

Case :

"products/all"  - Admin

"products/{id}" = USER


How to do that 

1. Add method level annotation for mention the authorization level 

@PreAuthorize("hasAuthority('ROLE_ADMIN')")

eg:

@GetMapping("/all")
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public List<Product> getAllTheProducts() {
return service.getProducts();
}

@GetMapping("/{id}")
@PreAuthorize("hasAuthority('ROLE_USER')")
public Product getProductById(@PathVariable int id) {
return service.getProduct(id);
}

But this is not enough

2. We need to enable Method level security in our "SecurityConfig" class. For that we add annotation "@EnableMethodSecurity"

sample as shown below

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {


3. Now you can try to access after login with credentials

eg: logged with ADMIN {Alex,Pwd1}

Then you can access only /products/all

If you try to access /products/{id}

you will most probably get a message like

--------------------------

Access to localhost was denied

You don't have authorization to view this page.

HTTP ERROR 403

------------------------



Below are two full code samples


package com.example.springsecurityjavaTechie.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;


@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

@Bean
UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
// authentication
UserDetails admin = User.withUsername("Alex")
.password(passwordEncoder.encode("Pwd1"))
.roles("ADMIN")
.build();
UserDetails user = User.withUsername("John")
.password(passwordEncoder().encode("Pwd2"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(admin, user);
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/products/welcome").permitAll()//just let any one access
.and()
.authorizeHttpRequests().requestMatchers("/products/**")
.authenticated().and().formLogin().and().build();

}

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


package com.example.springsecurityjavaTechie.controller;

import com.example.springsecurityjavaTechie.model.Product;
import com.example.springsecurityjavaTechie.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/products")
public class ProductController {

@Autowired
private ProductService service;

@GetMapping("/welcome")
public String welcome() {
return "Welcome this endpoint is not secure";
}

// @PostMapping("/new")
// public String addNewUser(@RequestBody UserInfo userInfo){
// return service.addUser(userInfo);
// }

@GetMapping("/all")
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public List<Product> getAllTheProducts() {
return service.getProducts();
}

@GetMapping("/{id}")
@PreAuthorize("hasAuthority('ROLE_USER')")
public Product getProductById(@PathVariable int id) {
return service.getProduct(id);
}
}


No comments:

Post a Comment