=================
Spring Security
=================
-> Security is very important for every web application.
-> To protect our application & application data we need to implement security logic.
-> Spring Security is one of the module of spring framework
-> Spring Security concept we can use to secure our web applications / REST APIs / Microservices.
-> To implment security, we need to know about two concepts
1) Authentication
2) Authorization
-> Authentication means verifying who can access our application (login check).
-> Authorization means verifying which user can access which functionality.
==============================
Working with Spring Security
==============================
-> To secure our spring boot application we need to add below starter in pom.xml file
org.springframework.boot
spring-boot-starter-security
Note-1: When we add this dependency in pom.xml file then by default our application will be secured with "http basic authentication"
Note-2: It will generate random password to access our application.
-> We need to use below credentials to access our application
Username : user
Password :
-> When we access our application url in browser then it will display "Login Form" to authenticate our request.
-> To access secured REST API from postman, we need to set Auth values in POSTMAN to send the request.
Auth : Basic Auth
Username : user
Password :
=====================================================
How to override Spring Security Default Credentials
=====================================================
-> To override Default credentials we can configre security credentials in "application.properties" file or "application.yml" file like below
spring.security.user.name=ashokit
spring.security.user.password=ashokit@123
==========================================
Spring Security In-Memory Authentication
==========================================
-> In Memory Authentication means storing user credentials in the program for Authentication Purpose.
## Note: This is used only for practice purpose, not recommended in real-time. ##
```
@Bean
public InMemoryUserDetailsManager inMemoryUsers() {
UserDetails u1 = User.withDefaultPasswordEncoder()
.username("ashokit")
.password("ashokit@123")
.build();
UserDetails u2 = User.withDefaultPasswordEncoder()
.username("raju")
.password("raju@123")
.build();
UserDetails u3 = User.withDefaultPasswordEncoder()
.username("john")
.password("john@123")
.build();
return new InMemoryUserDetailsManager(u1, u2, u3);
}
```
=====================================
How to secure specific URL Patterns
=====================================
-> When we add 'security-starter' in pom.xml then it will apply security filter for all the HTTP methods of our application.
-> But in reality we need to secure only few methods not all methods of our application.
/login-page : secuirty not required (anyone can access)
/transfer : secuirty required
/balance : security required
/about-us : security not required
/contact-us : security not required
-> In order to achieve above requirement we need to Customize Security Configuration in our project like below.
```
@Configuration
@EnableWebSecurity
public class AppSecurityConfigurer {
@Bean
public SecurityFilterChain securityConfig(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((req) -> req
.requestMatchers("/contact").permitAll()
.anyRequest().authenticated()
).httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
return http.build();
}
}
```
==============================================================================================
Requirement-1 : Develop REST API with Http Basic Authentication and configure auth credentials in application.properties file or use in-memory authentication.
Note: Test this rest api from browser and from postman.
Requirement-2 : Develop Consumer application to acces above secured rest api (above api).
================================================================================================
=> To access secured rest api we need to send basic auth credentials in request header like below
############ Authorization = Basic Base64.encode(uname:pwd) ############
================================================
Rest Template with Basic Authentication Header
================================================
String cred = uname+":"+pwd;
byte[] encodedCredentials = java.util.Base64.getEncoder().encode(cred);
String headerKey = "Authorization";
String headerValue = "Basic "+ new String(encodedCredentials);
HttpHeaders headers = new HttpHeaders();
headers.set(headerKey, headerValue);
HttpEntity entity = new HttpEntity(headers);
ResponseEntity res =
restTemplate.exchange(apiUrl, HttpMethod.GET, entity, String.class);
String body = res.getBody();
s.o.p(body);
================================================
WebClient with Basic Authentication Header
================================================
byte[] cred = java.util.Base64.getEncoder().encode(cred);
WebClient client = WebClient.create();
String response = client.get( )
.uri(apiUrl)
.header("Authorization", "Basic "+ new String(cred))
.header("key", "val")
.retrieve( )
.bodyToMono(String.class)
.block( );
s.o.p(response);
==============================================
Login and Registration using Spring Security
==============================================
=> Develop springboot rest api with below 2 functionalities using Spring Security.
1) User Registration (name, email, pwd and phno)
2) User Login (email, pwd)
Note-1: When user register, we need to store user data in database table by encrypting user pwd.
Note-2: When user try to login, if credentials are valid send welcome msg as response. If credentials are invalid then send "Invalid Credential" msg as response.
=====================
Development Process
=====================
## 1) Create Boot app with required dependencies ##
a) web-starter
b) data-jpa-starter
c) mysql
d) security-starter
e) devtools
## 2) Configure Data Source properties in application.properties file
## 3) Create Entity class & Repository interface ##
## 4) Create CustomerService class by implementing UserDetailsService class ##
```
@Service
public class CustomerService implements UserDetailsService {
@Autowired
private CustomerRepo customerRepo;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Customer c = customerRepo.findByEmail(email);
return new User(c.getEmail(), c.getPwd(), Collections.emptyList());
}
}
```
## 5) Create Security Config Class ##
```
@Configuration
@EnableWebSecurity
public class AppSecurityConfig {
@Autowired
private CustomerService customerService;
@Bean
public PasswordEncoder pwdEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(customerService);
authProvider.setPasswordEncoder(pwdEncoder());
return authProvider;
}
@Bean
public AuthenticationManager authManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
@Bean
public SecurityFilterChain security(HttpSecurity http) throws Exception{
http.authorizeHttpRequests( req -> {
req.requestMatchers("/register", "/login")
.permitAll()
.anyRequest()
.authenticated();
});
return http.csrf(csrf -> csrf.disable()).build();
}
}
```
## 6) Create RestController with required methods
```
@RestController
public class CustomerRestController {
@Autowired
private CustomerRepo customerRepo;
@Autowired
private PasswordEncoder pwdEncoder;
@Autowired
private AuthenticationManager authManager;
@PostMapping("/register")
public ResponseEntity saveCustomer(@RequestBody Customer customer) {
String encode = pwdEncoder.encode(customer.getPwd());
customer.setPwd(encode);
customerRepo.save(customer);
return new ResponseEntity<>("Customer Registered", HttpStatus.CREATED);
}
@PostMapping("/login")
public ResponseEntity loginCheck(@RequestBody Customer customer) {
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(customer.getEmail(), customer.getPwd());
try {
Authentication authenticate = authManager.authenticate(token);
if(authenticate.isAuthenticated()) {
return new ResponseEntity<>("Welcome to Ashok IT..!!", HttpStatus.OK);
}
} catch (Exception e) {
e.printStackTrace();
}
return new ResponseEntity<>("Invalid Credentials", HttpStatus.BAD_REQUEST);
}
}
```
## 7) Run the application and test it using postman
{
"name": "Sunil",
"phno" : 6686868,
"email" : "sunil@gmail.com",
"pwd" : "sunil@1233"
}
===============
Execution Flow
===============
Login Request---> Rest Controller ---> AuthManager ---> AuthProvider --> UserDtlsService --> Repository --> Database
======================
Spring Boot with JWT
======================
-> JWT stands for JSON Web Tokens.
-> JWT official Website : https://jwt.io/
-> Below is the sample JWT Token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30
-> JWT contains below 3 parts
1) Header
2) Payload
3) Signature
Note: JWT 3 parts will be seperated by using dot(.)
Note: Client application should send JWT Token to provider in below format
Authorization=Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbmlsQGdtYWlsLmNvbSIsImlhdCI6MTcyOTA1NzcxNiwiZXhwIjoxNzI5MDYxMzE2fQ.SJ1yonGgN85h7MewbsygPS8pN2JSHRn-6ICJ7bJVbvQ
=> To implement JWT Token Based API we will develop below 3 classes mainly
1) JWT Token Generation Class
- generateToken(String uname)
- validateToken(String uname)
2) JWT Token Validation Filter Class :: OncePerRequestFilter
- Check Authorization header presence in the request
- Retrieve Bearer Token From the header
- Validate Token
- If token is valid, update security context to process the request
3) SecurityConfig class to customize SecurityFilterChain
- permit "/api/register" and "/api/login" urls
- Authenticate any other request using Filter
==============================
Spring Boot with OAuth 2.0
==============================
=> OAuth 2.0 is an open standard authorization framework that allows third-party applications to access a user’s resources on another service, without sharing the user’s password.
=> Instead of giving your password to every app or website that wants to use your data (like Google contacts or Facebook photos), OAuth 2.0 lets you approve access using a special token.
=> It is commonley used in "Login in with Google / Login with Facebook / Login with GitHub"
==================================
How It Works (Simplified Flow):
==================================
1 : You click "Login with Google" on a website.
2 : The website redirects you to Google’s login and consent page.
3 : You approve access.
4 : Google sends back an access token to the website.
5 : The website uses the token to fetch your information from Google’s API.
========================
Development Process
========================
# 1) Create oAuth app in github.com
(Login --> Profile -> Settings --> Developer Settings --> OAuth Apps --> Create App --> Copy Client ID & Client Secret)
Client ID : Ov23liL7ZO8zro4ytgj5
Client Secret : 95f7b4e2e071f42c43e0519181248fe334bc0f73
# 2) Create Spring Boot application with below dependencies
a) web-starter
b) security-starter
c) oauth-client
# 3)Create Rest Controller with method
@RestController
public class WelcomeRestController {
@GetMapping("/")
public String welcome() {
return "Welcome to Ashok IT";
}
}
# 4) Configure GitHub OAuth App client id & client secret in application.yml file like below
spring:
security:
oauth2:
client:
registration:
github:
clientId:
clientSecret:
# 5) Run the application and test it.
=====================================================================================================================
Assignment : Spring Boot with oAuth using google account. Get username also from google and display that in response.
=====================================================================================================================