Tag: backend

  • Spring Security: Tìm hiểu về internal flow

    Spring Security: Tìm hiểu về internal flow

    Spring Security là gì?

    Spring Security là một framework được cung cấp bởi Spring cung cấp khả năng xác thực, bảo vệ, kiểm soát truy cập và có khả năng tuỳ biến cao. Tập trung chủ yếu vào Authentication và Authorization cho một ứng dụng Java.

    Giống như hầu hết các Spring projects khác, sức mạnh thực sự của Spring Security đến từ việc nó có thể dễ dàng mở rộng khi cần thiết với những yêu cầu cụ thể trong một dự án.

    Benefits/features chính:

    • Hỗ trợ authentication và authorization một cách toàn diện.
    • Ngăn chặn các nguy cơ bảo mật đến từ Cross-site Forgery, CSRF Attacks, ClickJacking,…
    • Hỗ trợ tích hợp với Spring Web MVC
    • Hỗ trợ tích hợp với Servlet API

    Internal Workflow: Cách Spring Security hoạt động?

    Dưới đây là workflow cách mà Spring Security mặc định (User Credentials) hoạt động:

    User Credentials Authentication workflow

    Ta hãy cùng đến với những objects chính có trong flow và tìm hiểu định nghĩa của chúng nhé.

    Spring Security Filters:

    Spring Security Authentication Filters là những filter sẽ nằm giữa client request với server. Khi nhận được request, các filter sẽ tách lọc những thông tin từ request thành các authentication details (username, password, roles,…). Default Spring Security sẽ sử dụng class UsernamePasswordAuthenticationFilter.

    UsernamePasswordAuthenticationFilter extends từ Abstract class AbstractAuthenticationProcessingFilter.

    Authentication: là một base object làm nhiệm vụ validate user credentials nhận được từ phía client. Ở behavior mặc định, Authentication object sẽ là class UsernamePasswordAuthenticationToken.

    UsernamePasswordAuthenticationToken sẽ được sử dụng để chứa user credentials.

    AuthenticationManager:

    AuthenticationManager là một interface với method authenticate() làm nhiệm vụ xác định những Authentication providers phù hợp nhất để xử lý Authentication object nhận được từ filters. AuthenticationManager sẽ nhận kết quả authenticate từ Provider (Success hoặc Not success). Nếu không success, nó sẽ thử một provider phù hợp khác.

    Ở behavior mặc định của Spring security, class ProviderManager sẽ được chọn để xử lý các request.

    ProviderManager implements interface AuthenticationManager.

    AuthenticationProvider:

    AuthenticationProvider là những classes implement interface AuthenticationProvider với method authenticate() làm nhiệm vụ xử lý các logic liên quan đến authentication. DaoAuthenticationProvider sẽ là authentication provider mặc định cho behavior mặc định của Spring Security.

    DaoAuthenticationProvider.

    UserDetailsService: là interface chứa thông tin, schema của user details. Ở behavior mặc định, Spring Security sẽ sử dụng class InMemoryUserDetailsManager, với method loadUserByUsername() để lấy ra thông tin của user từ memory của hệ thống.

    PasswordEncoder: là interface có nhiệm vụ encode, encrypt và decrypt password của user, validate và trả về kết quả valid/invalid cho Authentication Provider xử lý.

    Security Context:

    Sau khi Spring Security đã validate đủ, user details sẽ được lưu vào Security context. Ở lần truy cập tới, thông tin user sẽ được filter retrieve ở đây thay vì thực hiện đầy đủ các bước flow như ở trên.

    Kết luận

    Trên đây là tổng hợp về Spring Security cũng như một flow mặc định của Spring Security sẽ diễn ra như thế nào. Tất nhiên, còn rất nhiều những vấn đề to lớn khác từ Spring Security mà phạm vi bài viết không thể mô tả đủ. Hi vọng, qua bài viết trên, bạn đã có thể có cái nhìn tổng quan nhất về Spring Security, rất cảm ơn bạn đã dành thời gian ra để đọc qua bài viết trên của mình.

    Tài liệu tham khảo

    https://spring.io/projects/spring-security

    https://blog.knoldus.com/spring-security-internal/

    https://www.linkedin.com/pulse/how-does-spring-security-works-internally-ayush-jain/

  • [Spring] ApplicationContext trong Spring Framework

    [Spring] ApplicationContext trong Spring Framework

    Trong bài viết này chúng ta sẽ tìm hiểu chi tiết về ApplicationContext interface.

    ApplicationContext?

    Ta hãy cùng nhớ lại 2 khái niệm DI(Dependency Injection) và IoC(Inversion of Control) gây thương nhớ cho những developer của Spring framework. IoC Container chính là lõi của Spring Framework. IoC Container có chức năng tạo ra các đối tượng, liên kết chúng lại với nhau, cấu hình chúng, và quản lí vòng đời của chúng từ khi tạo ra đến khi bị hủy. IoC container sẽ sử dụng DI để quản lí các thành phần tạo nên một ứng dụng.

    Trong Spring framwork IoC được mô tả qua BeanFactory và ApplicationContext interface. BeanFactory là root interface truy cập vào Spring IoC, cung cấp chức năng cơ bản để quản lí Bean. Còn ApplicationContext là sub-interface cúa BeanFactory interface. Do đó, nó cung cấp tất cả các chức năng cơ bản của BeanFactory cùng nhưng chức năng tiên tiến hơn cho các ứng dụng Spring và phù hợp hơn cho những ứng dụng J2EE.

    Spring Bean

    Trước khi đi chi tiết hơn về ApplicationContext interface ta cần xem qua khái niệm về Spring Bean.

    In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.
    

    Hay hiểu đơn giản với các ứng dụng Spring, Bean là object được tạo ra và quản lí bới Spring IoC container.

    Cấu hình Bean trong Container

    Để ApplicationContext có thể quản lí được các Bean, ứng dụng phải cũng cấp cấu hình bean cho ApplicationContext container. Ta sẽ có những cách khác nhau cấu hình để cấu hình bean:

    1. XML-Based Configuration
    2. Java-Based Configuration
    3. Annotation-Based Configuration

    XML-Based Configuration

    Cuối cùng với cách cấu hình dựa trên XML, ta sẽ khai báo tất cả các cấu hình của Bean trong một file XML.

    Ta sẽ khai báo Bean cho class UserConfiguration trong một file user-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean id="userService" class="com.cuongnm.applicationcontext.UserService">
        <constructor-arg name="userRepository" ref="userRepository" />
      </bean>
      
      <bean id="userRepository" class="com.cuongnm.applicationcontext.UserRepository" />
    </beans>
    

    Java-Based Configuration

    Cấu hình dựa trên Java bằng cách sử dụng @Bean annotation bên trong 1 lớp @Configuration. Với mỗi @Bean annotation được khai báo đánh dấu cho một method để tạo ra 1 Spring Bean. Và những phương thức này đc chứa trong 1 class được đánh dấu là @Configuration – một class chứa các cấu hình Spring bean.

    Ví dụ:

    @Configuration
    public class UserConfig {
    
      @Bean
      public UserService userService() {
        return new AccountService(userRepository());
      }
    
      @Bean
      public UserRepository userRepository() {
        return new UserRepository();
      }
    }
    

    Bằng cách đưa ra @Configuration ta sẽ xử lí class UserConfig như thẻ bean trong XML

    Annotation-Based Configuration

    Để sử dụng được phương pháp này, đầu tiên ta sẽ cấu hình trong XML để cho phép sử dụng Annotation-Based Configuration trong ứng dụng.

    <context:annotation-config/>
    <context:component-scan base-package="com.cuongnm.applicationcontext"/>
    

    Thẻ context:annotation-config để khai báo cho việc sử dụng annotation-based mappings và thẻ context:component-scan với tham số base-package cho Spring tìm được package chưa các annotated classes.

    Sau đó, ta sẽ sử dụng các annotation được cung cấp bởi Spring để đánh dấu cho các class, method, constructor, field trong Java để cấu hình cho Bean như @Component, @Controller, @Service, @Repository, @Autowired.

    Ví dụ với class UserService được khai báo là một Bean sử dụng @Component annotation:

    @Component
    public class UserService {
      
    }
    

    Ta có thể lấy ra Bean này bằng cách:

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/user-bean-config.xml");
    UserService userService = context.getBean(UserService.class);
    assertNotNull(userService);
    

    Cách sử dụng ApplicationContext

    Cũng như việc cấu hình cho Bean thì cũng có rất nhiều cách sử dụng ApplicationContext interface.

    1) ClassPathXmlApplicationContext

    Phương pháp này sẽ tải các Bean config từ các file XML nằm trong đường dẫn classpath.

    ApplicationContext context = new ClassPathXmlApplicationContext ("user-bean-config.xml");
    

    2) FileSystemXmlApplicationContext

    Sử dụng các Bean config từ các file XML trong FileSystem hay từ URL.

    ApplicationContext context = new FileSystemXmlApplicationContext (“c: /myconfig.xml”);
    

    3) AnnotationConfigApplicationContext

    AnnotationConfigApplicationContext được sử dụng với Java-Based Configuration cho các cấu hình Bean.

    Ví dụ:

    public static void main(String[]args){
    /* Creating Spring IoC Container Without XML configuration file*/
    ApplicationContext context= new AnnotationConfigApplicationContext(UserConfig.class);
    MyBean beanObj = context.getBean(UserService.class);
    }
    

    Với ví dụ này ApplicationContext được lấy từ UserConfig class. Chúng ta lấy các cấu hình Bean từ một class được chú thích @Configuratation và nó sẽ được khai báo:

    @Configuration
    public class UserConfig {
    
      @Bean
      public UserService userService() {
        return new AccountService(userRepository());
      }
    
      @Bean
      public UserRepository userRepository() {
        return new UserRepository();
      }
    }
    

    3) XmlWebApplicationContext và AnnotationConfigWebApplicationContext

    XmlWebApplicationContext được sử dụng để đại diện cho Spring container trong ứng dụng Web. Và nó tải các cấu hình bean từ những file XML với mặc định từ đường dẫn “/WEB-INF/applicationContext.xml”. Chúng ta cũng có thể chỉ định được dẫn của nó qua tham số contextConfigLocation của ContextLoaderListener hoặc DispatcherServlet trong web.xml.

    Giống như XmlWebApplicationContext là class tương ứng với ClassPathXmlApplicationContext và FileSystemXmlApplicationContext và được sử dụng để tạo ra ApplicationContext cho các ứng dụng web, tương tự, AnnotationConfigWebApplicationContext là class tương ứng với AnnotationConfigApplicationContext.

    Lời kết

    Tóm tắt lại những gì mình muốn nói ở bài viết này, mục đích giúp chúng ta hiểu về ApplicationContext trong Spring, hiểu cách sử dụng, triển khai ApplicationContext. Cũng như cách gọi Spring container bằng ApplicationContext mang đến nhiều chức năng hơn so với BeanFactory.

    Bài viết được tham khảo từ “https://www.baeldung.com/spring-application-context“.

    Cảm ơn các bạn đã đọc bài viết!

  • [Spring] Sử dụng Spring ResponseStatusException

    [Spring] Sử dụng Spring ResponseStatusException

    Sử dụng Spring ResponseStatusException

    Giới thiệu

    Một ứng dụng RESTful, bằng cách trả về các HTTP status code trong HTTP response nó có thể thông báo về sự thành công hay thất bại của một HTTP request. Ví dụ như nếu người dùng request lên một id không hề tồn tại, các HTTP status code có thể giúp xác định được các vấn đề có thể xảy ra khi xử lí request.

    Trong Spring chúng ta cũng có rất nhiều cách để đặt HTTP status code cho một HTTP response. Tuy nhiên trong bài viết này mình sẽ giới thiệu về một class mới được giới thiệu trong Spring 5 đó chính là ResponseStatusException sẽ hỗ trợ cho ta việc áp dụng HTTP status code.

    @ResponseStatus

    Trước khi tìm hiểu về ResponseStatusException , ta sẽ tìm hiểu qua về @ResponseStatus annotation. Annotation này được giới thiệu trong Spring 3 để giải quyết vấn đề áp dụng HTTP status code cho HTTP response.

    Với annotaion này chúng ta sẽ sử dụng để định nghĩa status code và reason cho HTTP response:

    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Image not found")
    public class ImageNotFoundException extends Exception{
        //...
    }
    

    Ở trong ví dụ này, nếu Exception được đưa ra trong một xử lí HTTP request, thì trong response sẽ bao gồm HTTP status code được chỉ định sẽ là 404.

    Tuy nhiên với phương pháp sử dụng @ResponseStatus ta có một nhược điểm là nó sẽ tạo ra mối quan hệ phụ thuộc chặt chẽ vói Exception. Và như trường hợp ta xét ở trên thì tất cả các Exception có kiểu ImageNotFoundException khi được đưa ra thì đều cho ta một response với thông báo lỗi và status code là như nhau trong mọi trường hợp.

    ResponseStatusException

    ResponseStatusException được tạo ra nhằm thay thế cho @ResponseStatus và là một base class cho các exception được sử dụng đề apply các HTTP status cho response. Và đây cũng là một RuntimeException.

    Với ResponseStatusException class sẽ cung cấp cho ta 3 contructor:

    Với các đối số truyền vào cho contructor method:

    • status – HTTP status được set cho HTTP response
    • reason – message được hiển thị để giải thích cho exception
    • cause – là một java.lang.Throwable nguyên nhân của ResponseStatusException

    Những điểm mạnh cảu việc dùng ResponseStatusException class:

    • Thứ nhất, việc khai báo và sử dụng dễ dàng
    • Thứ hai, các exception cùng loại ta có thể xử lí riêng biệt và có thể linh hoạt các stutas code khác nhau có thể được set trong response, giảm sự phụ thuộc vào nhau.
    • Thứ ba, ta có thể tránh được việc phải tạo các class exception không cần thiết.
    • Và cuối cùng, class cấp cho ta nhiều quyền hơn trong việc xử lí exception, vì các exception được tạo theo chương trình nên được kiểm soát tốt hơn.

    Ví dụ

    Bây giờ, hãy xem một ví dụ về cách sử dụng ResponseStatusException trong thực tế:

    Ta có 1 class ToDoController khái báo “/todo” mapping truyền vào tham số id để lấy ra Todo object tương ứng

    @RestController
    public class ToDoController {
    
        @Autowired
        private ToDoService toDoService;
    
        @GetMapping(value = "/todo")
        public ToDo getTodo(@RequestParam(value = "id", required = false) Long id) {
            try {
                return toDoService.getTodo(id);
            } catch (TodoNotFoundException e) {
                throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Todo not found", e);
            }
        }
    
    }
    

    Với một exception được khai báo

    public class TodoNotFoundException extends Exception{
    
        public TodoNotFoundException(String errorMessage){
            super(errorMessage);
        }
    }
    

    Spring sẽ cung cấp cho ta một “/error” mapping sẽ trả về response dưới định dạng JSON với HTTP status. Trong ví dụ này khi truyền vào id không hề tồn tại chương trình sẽ trả về ResponseStatusException với response chứa status code tương ứng.

    Đây sẽ là response trong trường hợp có exception (ta sẽ dùng Postman để gửi request):

    Để xem được message về lỗi trong response ta sẽ thêm thuộc tính server.error.include-message=always. Khi đó response trả về sẽ có nội dung:

    {
        "timestamp": "2021-08-03T01:35:20.878+00:00",
        "status": 404,
        "error": "Not Found",
        "message": "Todo not found",
        "path": "/todo"
    }
    

    Ngoài ra với lợi ích là tính linh hoạt khi có thể gán các status code khác nhau cho cùng một exception ta có thể thứ với một ví dụ khác:

    @GetMapping(value = "/todo")
        public ToDo getTodo(@RequestParam(value = "id", required = false) Long id) {
            try {
                return toDoService.getTodo(id);
            } catch (TodoNotFoundException e) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Provide correct Todo Id", e);
            }
        }
    

    Và response trả về sẽ là:

    {
        "timestamp": "2021-08-03T01:57:41.502+00:00",
        "status": 400,
        "error": "Bad Request",
        "message": "Provide correct Todo Id",
        "path": "/todo"
    }
    

    Lời kết

    Như vậy trong bài viết này, chúng ta đã cùng tìm hiểu về ResponseStatusException – một cách tốt hơn để tạo một HTTP status code trong HTTP response so với annotation @ResponseStatus. Tuy nhiên với việc nên thận trọng với việc sử dụng vì nếu không có phương pháp xử lí exception thống nhất thì việc thực thi một số quy ước trên toàn ứng dụng sẽ khó khăn và có thể xảy ra code bị trùng lặp.

    Cảm ơn các bạn đã đọc bài viết!

    Tài liệu tham khảo: https://www.baeldung.com/spring-response-status-exception

  • Hướng dẫn sử dụng Project Lombok

    Hướng dẫn sử dụng Project Lombok

    Hướng dẫn sử dụng Project Lombok

    Chinh chiến với Java nhiều năm, bạn có cảm thấy nhàm chán khi làm việc với những đoạn code theo khuôn mẫu của nó hay lười biếng phải khai báo các phương thức Getter, Setter cho các class Java? Nếu câu trả lời là có thì hãy sử dụng Project Lombok. Vậy Project Lombok là gì?

    • Lombok?
    • Cài đặt
    • Sử dụng Lombok
    • Lời kết

    Lombok?

    Lombok là một thư viện, một plugin, giúp chúng ta giảm thiểu các đoạn code thừa (boilerplate) bằng cách tự động sinh ra các hàm GetterSetterConstructor, v.v..

    Lombok giúp chúng ta generate code một cách tự động nhưng không giống như cách các IDE làm cho chúng ta. Các IDE generate các phương thức Getter, Setter và một số phương thức khác trong các tập tin .java. Lombok cũng generate các phương thức đó nhưng là trong các tập tin .class file. Không những làm cho code sáng sửa mà còn trông rất hợp lý, dễ quản lý hơn giúp developer tập trung vào tầng nghiệp vụ và logic thay vì mất thời gian làm những việc thừa thãi.

    Cài đặt

    Để sử dụng Lombok trong project ta cần:

    Bước 1

    Thêm lib vào project bằng Maven hoặc Gradle

    Maven

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
        <scope>provided</scope>
    </dependency>
    

    Gradle

    
    // https://mvnrepository.com/artifact/org.projectlombok/lombok
    compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.20'
    

    Bước 2

    Đến đây có thể bạn sẽ thắc mắc tại sao đã thêm Lombok vào project rồi mà còn phải cài thêm Lombok Plugin vào IDE nữa???

    Ví dụ bạn muốn sử dụng Lombok để generate Get/Set thì nó sẽ tự động thêm code vào class đó trước khi thành file .jar. Nhưng các IDE thì chỉ nhìn thấy các dòng code hiện tại của bạn và tham chiếu tới nó, điều này sẽ dẫn đến những thông báo lỗi khi bạn sử dụng hàm Get/Set này.

    Nên để IDE hiểu rằng các class đã có các hàm Get/Set rồi, thì bạn phải cài thêm Lombok Plugin.

    Bây giờ ta sẽ cài đặt cho IntelliJ IDEA

    Với IntelliJ IDEA version 2020.3 trở lên thì IDE đã hỗ trợ Lombok mà ko cần cài plugin(phần hướng dẫn này cho version trước 2020.3 )

    Vào File -> Setting -> Plugin …

    Search “Lombok”, chọn Lombok Plugin và Install.

    Sử dụng Lombok

    Lombok dùng các Annotation để khai báo

    @Data

    Ví dụ này 2 đoạn code sẽ tương đương

    public class User {
    
        private String name;
    
        private int age;
    
        public User() {
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User: " + name
                    + " - " + age;
        }
    }
    
    import lombok.Data;
    
    @Data
    public class User {
    
        private String name;
    
        private int age;
    }
    

    Khi bạn đánh dấu 1 class là @Data, thì nó sẽ generate ra Constructor rỗng hoặc có tham số theo yêu cầu, toàn bộ Get/Set, hàm equals, hashCode, toString().

    @NoArgsConstructor@RequiredArgsConstructor@AllArgsConstructor

    Các annotation được dùng trong trường hợp bạn muốn định nghĩa các Contructor theo yêu cầu khác nhau:

    • @NoArgsConstructor: Hàm khởi tạo rỗng, đã đề cập ở trên
    • @RequiredArgsConstructor: Hàm khởi tạo chứa tất cả thuộc tính, ví dụ Champion(String name, String type)
    • @AllArgsConstructor: Hàm khởi tạo theo yêu cầu. Bạn chỉ muốn hàm khởi tạo có vài thuộc tính do bạn chọn thôi, thì bạn thêm final trước thuộc tính trong class, nó sẽ tự sinh ra Constructor như thế.

    @Getter@Setter

    Được sử dụng trong trường hợp chỉ muốn generate Get/Set và không muốn dùng @Data vì có chức năng không cần thiết.

    import lombok.Getter;
    import lombok.Setter;
    
    @Getter
    @Setter
    public class User {
    
        private String name;
    
        private int age;
    }
    

    @Builder

    Thông thường, khi chúng ta cần khởi tạo một đối tượng với rất nhiều thông tin, chúng ta có thể sử dụng Builder Pattern để làm điều này.

    Ví dụ với class User như sau:

    public class Users {
    
        private String name;
    
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User: " + name
                    + " - " + age;
        }
    }
    

    Để tạo đối tượng User với tất cả các thông tin sử dụng Builder Pattern, chúng ta cần tạo một đối tượng UserBuilder như sau:

    public class UserBuilder {
    
        private Users user;
    
        public UserBuilder() {
            user = new User();
        }
    
        public UserBuilder name(String name){
            user.setName(name);
            return this;
        }
    
        public UserBuilder age(int age){
            user.setAge(age);
            return this;
        }
    
        public Users build(){
            return user;
        }
    }
    

    Và dùng UserBuilder này:

    Users users = new UserBuilder()
                    .name("CuongNM")
                    .age(20)
                    .build();
    

    Chắc hẳn ai cũng ngại khi viết 1 class Builder cổ điển như trên, tự dưng phải tạo thêm 1 class nữa, gấp đôi số lượng thuộc tính khai báo, gấp đôi số hàm cần viết.

    Với Lombok vấn đề này đc giải quyết rất nhanh gọn

    @Data
    @Builder
    public class Users {
    
        private String name;
    
        private int age;
    }
    
    Users users = Users.builder()
                    .name("CuongNM")
                    .age(20)
                    .build();
    

    Logging với Project Lombok(@Slf4j)

    Thông thường, khi chúng ta sử dụng các Logging frameworks như Log4J, Logback hay Simple Logging Facade for Java (SLF4J), ta sẽ khai báo như sau:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
     
    public class Example {
     
        public static final Logger LOGGER = LoggerFactory.getLogger(Example.class);
     
        public void print(String message) {
            LOGGER.info(message);
        }
    }
    

    Nhưng đối với Lombok, ta chỉ cần dùng annotation dành cho Logging framework mà chúng ta muốn sử dụng mà thôi, sau đó thì có thể sử dụng như bình thường. Như ví dụ ở đây, mình đang sử dụng Simple Logging Facade for Java(SLF4J) để logging thì mình sẽ khai báo annotation @Slf4j của Lombok dành cho thư viện này như sau:

    import lombok.extern.slf4j.Slf4j;
     
    @Slf4j
    public class Example {
     
        public void print(String message) {
            log.info(message);
        }
    }
    

    Lời kết

    Lombok sinh ra để giúp cho code của chúng ta trở nên ngắn gọn dễ hiểu hơn và nó còn rất nhiều tính năng hay ho khác. Trong khuôn khổ bài viết này mình chỉ giới thiệu về các tính năng cơ bản của Lombok và được mình sử dụng nhiều nhất trong suốt quá trình làm việc.

    Cảm ơn các bạn đã đọc bài viết! Các bạn có thể tìm hiểu thêm tại trang chủ của Lombok.

    Tác giả

    [email protected]

  • HTTP vs HTTPS: Làm thế nào để website bảo mật hơn với SSL

    HTTP vs HTTPS: Làm thế nào để website bảo mật hơn với SSL

    Vào tháng 8 năm 2014, Google công bố sử dụng HTTPS để khắc phục những vẫn đề bảo mật mà phương thức HTTP đang gặp phải.

    Đối với hầu hết các công ty, việc Google khuyến cáo sử dụng HTTPS là lý do để thực hiện chuyển đổi sang giao thức đó, nhưng bản thân mỗi chúng ta cũng cần hiểu sự khác biệt giữa chúng – ưu và nhược điểm của HTTP và HTTPS. Tôi sẽ bắt đầu bằng việc giới thiệu tổng quan về giao thức HTTP và sau đó xem xét lý do tại sao Google muốn các trang web chuyển đổi sang sử dụng HTTPS.

    HTTP là gì, hoạt động như thế nào, và tại sao nó không được bảo mật?

    HTTP – HyperText Transfer Protocol, là một giao thức đã tồn tại hơn 15 năm, dùng để truyền tải thông tin qua Internet.

    Cũng như nhiều giao thức khác, HTTP hoạt động theo mô hình Client – Server. Trình duyệt web tạo request được gọi là Client, nơi nhận và phản hồi request đó là Server.

    Giả sử, bạn đang ngồi trong quán cafe và thử đăng nhập Facebook thông qua wifi của quán (giả định là Facebook đang dùng HTTP). Mạng wifi của quán là public, bất cứ ai kết nối với nó đều có thể truy cập dữ liệu đang được chuyển giao.

    Bây giờ chúng ta hãy xem những gì đang xảy ra với dữ liệu của bạn nếu như website sử dụng HTTP.

    Dữ liệu ở đây là bao gồm tất cả thông tin đăng nhập, mật khẩu, … cho tài khoản Facebook của bạn.

    Để đăng nhập vào Facebook, bạn cần nhập các thông tin như email, số điện thoại và mật khẩu. Ngay khi bạn nhấp vào nút đăng nhập, dữ liệu của bạn sẽ được gửi đến Server của Facebook. Server nhận dữ liệu, và xác thực nó. Nếu thông tin nhập là chính xác, Server sẽ gửi về HTTP status là “OK”, và bạn được đăng nhập vào tài khoản của mình. Mọi thứ có vẻ ez.

    Nhưng vấn để xảy ra ở đây là, nếu dữ liệu của bạn gửi lên server thông qua HTTP, thì nó sẽ không được mã hóa (HTTP không mã hóa dữ liệu) và vì vậy, bất kỳ dữ liệu nào được truyền thông qua giao thức HTTP đều có thể bị đánh cắp hoặc thay đổi từ bên thứ ba.

    Có thể bạn chưa bao giờ nghe tới Network sniffing attack, nhưng loại tấn công đó khá phổ biến.

    Sniffing attacks là một loại tấn công mà các Hacker sử dụng để lấy cắp thông tin “nhạy cảm” của bạn (vd: password, creadit card, users id, …).

    Để thực hiện việc này, các hacker thường sử dụng Sniffer – một chương trình có thể bắt được các gói tin truyền qua mạng.

    Sniffer là công cụ để phân tích và khắc phục các sự cố mạng thông qua việc bắt các gói tin, nhưng Hacker có thể lợi dụng điều đó để sử dụng chúng vào mục đích bất chính.

    Nếu các gói tin không được mã hóa, dữ liệu trong các gói tin này nó thể được lấy bởi một Sniffer. Sniffer sẽ phân tích và đọc nội dung gói tin, từ đó, các hacker đã có thể lấy được các thông tin private của bạn một cách dễ dàng.

    Như chúng ta đã thấy, HTTP có một điểm yếu chí cmn mạng – thông tin chuyển tới Server thông qua HTTP không được mã hóa. Điều đó, về mặt lý thuyết, có thể bị chặn bởi Hacker bất cứ lúc nào.

    Đối với những trang web thuần túy để đọc báo hay xem thông tin thì không có vấn đề gì lớn. Nhưng nó rất nguy hiểm khi bạn thực hiện các giao dịch trực tuyến, mà trong đó phải cung cấp các thông tin cá nhân quan trọng như giao dịch ngân hàng, mua sắm, …

    Tuy nhiên, điểm yếu đó của HTTP có thể được giải quyết dễ dàng bằng cách sử dụng 1 protocol khác – HTTPS.

    HTTPS ngoài Sniffing attacks ra cũng có thể bảo vệ bạn khỏi những kiểu tấn công khác như man-in-the-middle attacksDNS rebindingreplay attacks. Nhưng trong bài viết này, tôi chỉ để cập tới cách để HTTPS bảo vệ bạn khỏi Sniffing attacks đã nói ở trên thôi.

    HTTPS là gì và làm thế nào nó có thể bảo vệ website của bạn

    Giống như HTTP, HTTPS cũng là một giao thức giúp truyền thông tin giữa Client và Server. (Nó là một phiên bản của HTTP với thêm chứ “S” ở cuối – viết tắt của “Secure”). HTTPS bảo mật dữ liệu của bạn bằng cách sử dụng giao thức TSL (Transport Layer Security) hay còn gọi là SSL. Nhưng SSL là gì?

    SSL là tiêu chuẩn bảo mật cung cấp 3 lớp bảo vệ:

    • Mã hóa (Encryption): tất cả dữ liệu được gửi giữa browsers (Client) và Server đều được mã hóa. Nếu Hacker lấy được gói tin đó, cũng không thể giải mã được.
    • Toàn vẹn dữ liệu (Data integrity): Đảm bảo dữ liệu truyền đi không thể sửa đổi hoặc bị hỏng mà không bị phát hiện.
    • Xác thực (Authentication): Xác minh xem bạn thực sự đang giao tiếp với Server đã định hay không.

    Để ý một chút, khi truy cập website sử dụng HTTPS, trên url của bạn sẽ hiển thị ra chữ màu xanh như sau:

    Hoạt động của SSL

    SL sử dụng cái gọi là Public Key Cryptography hoặc hệ thống Public Key Infrastructure (PKI). Hệ thống PKI (key không đối xứng) sử dụng 2 key khác nhau để mã hóa thông tin: public key và private key. Bất cứ thứ gì được mã hóa bằng public key đều chỉ có thể giải mã bằng private key tương ứng và ngược lại.

    Lưu ý rằng, private key – giống như cái tên của nó, nên được bảo vệ kỹ và chỉ được truy cập bởi chính owner mà thôi. Với một trang web, private key phải được giữ an toàn trên Server. Nhưng ngược lại, public key lại được cấp phát công khai cho bất kỳ ai, và tất cả mọi người đều cần nó để giải mã thông tin đã được mã hóa trước đấy bằng private key. Bây giờ, chúng ta đã hiểu cách làm việc của cặp public key và private key, ta sẽ tiếp tục mô tả quá trình hoạt động SSL thông qua từng bước như sau.

    Giả sử bạn truy cập 1 website có sử dụng HTTPS:

    • Bước 1: Thiết lập một “giao tiếp” an toàn giữa Server và Client – còn được gọi là Handshake (bắt tay). Quá trình Handshake được bắt đầu khi browsers truy cập trang web thông qua url. Bằng cách request trên, Client sẽ khởi tạo kết nối SSL với Server cùng với thông tin về phiên bản và kiểu mã hóa. Việc Client gửi request và khởi tạo kết nối SSL được gọi là client hello.
    • Bước 2: Bước tiếp theo được gọi là server hello. Sau khi nhận được yêu cầu từ Client, Server trả về cho Client SSL certificate cùng với public key của nó. Hoàn tất quá trình chào hỏi xã giao.
    • Bước 3: Client nhận được dữ liệu từ Server, browser sẽ xác minh SSL certificate đó. Những certificate này được kiểm soát bởi các tổ chức bảo mật (Certificate Authority) như Symantec, Comodo, GoDaddy. SSL Certificate là một khối dữ liệu bao gồm nhiều thông tin về server như:
      • Tên domain.
      • Tên công ty sở hữu.
      • Thời gian certificate được cấp.
      • Thời hạn certificate.
      • Public key.
    • Bước 4: Sau khi xác minh xong, Browser sẽ sinh ra 1 Key - K và được mã hóa bởi public key nhận được từ bước 2. K sẽ được sử dụng để mã hóa tất cả dữ liệu truyền tải giữa Client và Server.
    • Bước 5: Do quá trình mã hóa dữ liệu sử dụng PKI (key đối xứng), nên Client cần gửi cho Server cái khóa K này để giải mã gói tin. Server sẽ dùng private key để giải mã gói tin này và lấy được thông tin về khóa K.
    • Bước 6: Từ đây, các thông tin truyền tải giữa Client và Server đều được mã hóa bằng khóa K. Khóa K này là unique và chỉ có hiệu lực trong thời gian Session đó tồn tại.

    Việc sử dụng HTTPS sẽ bảo vệ trang web của bạn tới những kiểu tấn công mà tôi đã đề cập trước đó. Bạn có authentication, bạn có thể biết rằng mình đang giao tiếp một cách an toàn với Server dự định. Dữ liệu của bạn được mã hóa encryption – ngay cả khi sniffer lấy được gói tin, cũng không thể giải mã được nội dung bên trong. Và tất nhiên bạn có được toàn vẹn dữ liệu data integrity, vì vậy bạn có thể truyền những dữ liệu nhạy cảm mà không cần lo lắng về việc nó bị hỏng hoặc sửa đổi mà không phát hiện ra.

    Bạn có nên sử dụng HTTPS

    Trước khi đưa ra quyết định sử dụng HTTPS thay cho HTTP, tôi sẽ tổng hợp những lợi ích chính nếu website của bạn sử dụng HTTPS:

    • Security: Tất cả thông tin truyền tải giữa Client và Server đều được mã hóa và xác minh. Điều này giúp bạn chống được một số kiểu tấn công của hacker như man-in-the-middle attacksDNS rebindingreplay attacks.
    • Trust: Người dùng sẽ cảm thấy an tâm với trang web của bạn hơn. HTTPS giúp xây dựng lòng tin với họ, nhất là khi web của bạn cung cấp các dịch vụ dính đến tiền (yaoming).
    • SEO: Việc sử dụng HTTPS sẽ tăng thứ hạng tìm kiếm trang web của bạn trên các search engine.

    Nguồn: