post-image

Spring Boot OAuth2 Part 1 – Getting The Authorization Code

Spring Boot Starters & Common Configurations

NỘI DUNG BÀI VIẾT

Trong hướng dẫ trước, mình đã có 1 bài viết tổng quan về OAuth. Trong bài hướng dẫn này, mình sẽ triển khai Client Application và Resource Server. Quy trình sẽ thực hiện như sau:

  • Resource Owner sẽ yêu cầu Client Application lấy một số dữ liệu từ Resource Server.
  • Resource Server yêu cầu Resource Owner xác thực chính nó và cho phép chia sẻ dữ liệu.
  • Sau khi xác thực thành công, Resource Server chia sẻ mã ủy quyền với client application.

Trong hướng dẫn tiếp theo, chúng ta sẽ xem cách sử dụng mã ủy quyền.

boot-40_8

Resource Server Application

Maven Project:

boot-401_1

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.oauth</groupId>
    <artifactId>boot-sec</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>boot-resource-server</name>
    <description>Demo project for Spring Boot OAuth</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>Code language: HTML, XML (xml)
SpringBootResourceServerApplication.java
package com.javainuse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootResourceServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootResourceServerApplication.class, args);
    }
}Code language: JavaScript (javascript)
Employee.java
package com.javainuse.model;

public class Employee {

    private String empId;
    private String empName;

    public String getEmpId() {
        return empId;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

}Code language: JavaScript (javascript)
EmployeeController.java
package com.javainuse.controllers;

import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.javainuse.model.Employee;

@Controller
public class EmployeeController {

    @RequestMapping(value = "/user/getEmployeesList", produces = "application/json")
    @ResponseBody
    public List<Employee> getEmployeesList() {
        List<Employee> employees = new ArrayList<>();
        Employee emp = new Employee();
        emp.setEmpId("emp1");
        emp.setEmpName("emp1");
        employees.add(emp);
        return employees;

    }

}Code language: JavaScript (javascript)

Cuối cùng, mình sẽ cấu hình bảo mật. Trong cấu hình này, mình chỉ định các URL nào sẽ bị chặn và sẽ được truy cập bởi người dùng nào và có vai trò nào.

package com.javainuse.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class EmployeeSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/user/getEmployeesList")
            .hasAnyRole("ADMIN").anyRequest().authenticated().and().formLogin()
            .permitAll().and().logout().permitAll();

        http.csrf().disable();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationMgr) throws Exception {
        authenticationMgr.inMemoryAuthentication().withUser("admin").password("admin")
            .authorities("ROLE_ADMIN");
    }
}Code language: JavaScript (javascript)

Tiếp theo, mình cấu hình máy chủ ủy quyền bằng cách sử dụng @EnableAuthorizationServer.

Máy chủ được tùy chỉnh bằng cách mở rộng class AuthorizationServerConfigurerAdapter cung cấp các phương thức trống cho giao diện AuthorizationServerConfigurer.

.Máy chủ ủy quyền không bảo mật điểm cuối ủy quyền, tức là /oauth/authorize. Phương thức cấu hình ở đây sẽ chèn trình quản lý xác thực Spring Security.

Sử dụng trong memory client service, mình thiết lập các client có thể truy cập vào server.

package com.javainuse.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("javainuse").secret("secret").authorizedGrantTypes("authorization_code")
            .scopes("read").authorities("CLIENT");
    }
}Code language: CSS (css)

Client Application

Mình sẽ tạo 1 client application. Ứng dụng này sẽ hỏi resource server mà mình đã tạo ở trên cho dữ liệu JSON. Như đã giải thích trước đó, mình đã giả định rằng Client Application này đã được đăng ký với Resource Server và nó có client id là ‘javainuse’ và secret key là ‘secret’/

Theo thông số kỹ thuật của OAuth, nó sẽ yêu cầu ủy quyền tại uri /authorize.

Mình sẽ thay đổi uri mặc định này theo yêu cầu nhưng mình sẽ chỉ sử dụng uri mặc định trong ví dụ này.

Cùng với uri mặc định, chúng ta nên gửi các parameter sau:

  • response_type – REQUIRED. Value phải đặt thành “code”.
  • client_id – REQUIRED. Client identìier có được trong quá trình đăng ký. Trong trường hợp này nó là ‘javainuse’.
  • redirect_uri – OPTIONAL, Sau khi xác thực thành công, resource owner phải chuyển đến url này.
  • scope – OPTIONAL. Phạm vi của yêu cầu truy cập. Có thể là Read or Write. Mình sẽ sử dụng giá trị Read.

Các thông số trên phải là định dạng “application/x-www-form-urlencoded”.

Maven Project:

boot-40_3

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.oauth</groupId>
	<artifactId>boot-client-application</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>boot-client-application</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.2.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>Code language: HTML, XML (xml)
EmployeeController.java:
package com.javainuse.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class EmployeeController {

    @RequestMapping(value = "/getEmployees", method = RequestMethod.GET)
    public ModelAndView getEmployeeInfo() {
        return new ModelAndView("getEmployees");
    }
}Code language: CSS (css)

application.properties:

spring.mvc.view.prefix:/WEB-INF/jsp/
spring.mvc.view.suffix:.jsp

server.port:8090Code language: JavaScript (javascript)

Cuối cùng là SpringBootFormHandingApplication.java.

package com.javainuse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootFormHandingApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootFormHandingApplication.class, args);
    }
}

getEmployees.jsp.

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Get Employees</title>
</head>
<body>
    <h3 style="color: red;">Get Employee Info</h3>

    <div id="getEmployees">
        <form:form action="http://localhost:8080/oauth/authorize"
            method="post" modelAttribute="emp">
            <p>
                <label>Enter Employee Id</label>
                 <input type="text" name="response_type" value="code" /> 
                 <input type="text" name="client_id" value="javainuse" />
                 <input type="text" name="redirect_uri" value="http://localhost:8090/showEmployees" />
                 <input type="text" name="scope" value="read" /> 
                 <input type="SUBMIT" value="Get Employee info" />
        </form:form>
    </div>
</body>
</html>Code language: HTML, XML (xml)

Tiếp theo, khởi động boot-resource-server và boot-client-application. Truy cập localhost:8090/getEmployees.

Click button Get Employee.

boot-40_4

Nhập thông tin

boot-401_2

Cho phép Resource Owner chia sẻ dữ liệu.

boot-40_6

Chúng ta có thể thấy rằng Resource Owner chia sẻ mã ủy quyền với Client Application.

Nguồn:

https://www.javainuse.com/spring/spring-boot-oauth-authorization-code

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *