================= 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. =====================================================================================================================