OAuth2 Authorization Server
基于Spring Security 5 的 Authorization Server的写法
先看演示

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cjs.example.oauth2</groupId>
    <artifactId>cjs-authorization-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cjs-authorization-server</name>
    <properties>
        <java.version>1.8</java.version>
        <docker.image.prefix>cjssso</docker.image.prefix>
    </properties>
    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
            <version>0.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <!-- https://www.webjars.org/documentation#springboot -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
            <version>0.50</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>5.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <!-- https://github.com/spotify/docker-maven-plugin -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.2</version>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
application.yml
server:
  port: 9000
#  servlet:
#    context-path: /uaa
logging:
  level:
    root: debug
Security配置
package com.cjs.example.oauth2.config;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
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.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
/**
 * @Author ChengJianSheng
 * @Date 2022/3/29
 */
@Configuration
public class OAuth2AuthorizationServerSecurityConfiguration {
    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        return http.formLogin(Customizer.withDefaults()).build();
    }
    @Bean
    @Order(2)
    public SecurityFilterChain standardSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorize) -> authorize
                .antMatchers("/webjars/**", "/login", "/login-error").permitAll()
                .anyRequest().authenticated())
                .formLogin().loginPage("/login").failureUrl("/login-error");
        return http.build();
    }
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient client1 = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("client-1")
                .clientSecret("$2a$10$zNvOs9Ex0cD794OyWwDIXutF7F4hHYjLuEwI.U30p3nNIyumfON42")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .redirectUri("http://127.0.0.1:8081/message/login/oauth2/code/mycustom")
                .redirectUri("http://127.0.0.1:8081/message/authorized")
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
                .build();
        RegisteredClient client2 = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("client-2")
                .clientSecret("$2a$10$csxC.p5gNQbnpv8Mt5dqPevS66QL2USHERtQ8hEA1TWETIk1Zo3SS")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("http://www.baidu.com")
                .scope("message:read")
                .build();
        return new InMemoryRegisteredClientRepository(client1, client2);
    }
    @Bean
    public JWKSource jwkSource(KeyPair keyPair) {
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }
    @Bean
    public JwtDecoder jwtDecoder(KeyPair keyPair) {
        return NimbusJwtDecoder.withPublicKey((RSAPublicKey) keyPair.getPublic()).build();
    }
    @Bean
    public ProviderSettings providerSettings() {
        return ProviderSettings.builder().issuer("http://localhost:9000").build();
    }
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails userDetails = User.withUsername("zhangsan")
                .password("$2a$10$5nlwTDZ9LNbz7UMKcseY3u6YqbkGrMe2tQirfrwrCJAKrDAM78bUa")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(userDetails);
    }
    public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("123456"));
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }
}
自定义登录页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Spring Security OAuth 2.0 Sample</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.css" th:href="@{/webjars/bootstrap/css/bootstrap.css}" />
</head>
<body>
<div class="container">
    <h1>Login</h1>
    <p th:if="${loginError}" style="font-weight:bold;color:red;">Wrong username or password</p>
    <form th:action="@{/login}" method="post">
        <div class="form-row">
            <div class="form-group">
                <label for="username">Username</label>
                <input type="text" id="username" name="username" placeholder="请输入用户名" autofocus="autofocus" class="form-control">
                <small class="form-text text-muted">user1 / password</small>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group">
                <label for="password">Password</label>
                <input type="password" id="password" name="password" placeholder="请输入密码" class="form-control">
            </div>
        </div>
        <div class="form-row">
            <div class="form-group">
                <label for="verificationCode">验证码</label>
                <input type="text" id="verificationCode" name="verificationCode" placeholder="请输入验证码" class="form-control">
            </div>
        </div>
        <button type="submit" class="btn btn-primary">登录</button>
    </form>
</div>
<script src="/webjars/jquery/jquery.min.js" th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script src="/webjars/bootstrap/js/bootstrap.min.js" th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>
</body>
</html>
默认的Controller
package com.cjs.example.oauth2.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
/**
 * @Author ChengJianSheng
 * @Date 2022/4/2
 */
@Controller
public class DefaultController {
	@GetMapping("/")
	public String root() {
		return "redirect:/index";
	}
	@GetMapping("/index")
	public String index() {
		return "index";
	}
	@GetMapping("/login")
	public String login() {
		return "login";
	}
	@GetMapping("/login-error")
	public String loginError(Model model) {
		model.addAttribute("loginError", true);
		return login();
	}
}
获取token
GET http://localhost:9000/oauth2/authorize?response_type=code&client_id=client-2&redirect_uri=http://www.baidu.com
POST /oauth2/token HTTP/1.1
Host: localhost:9000
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=xxx&redirect_uri=http://www.baidu.com

抓包


项目结构

参考
https://github.com/jgrandja/spring-security-oauth-5-2-migrate/tree/main/client-app
OAuth2 Authorization Server的更多相关文章
- Spring Cloud(6.1):搭建OAuth2 Authorization Server
		
配置web.xml 添加spring-cloud-starter-security和spring-security-oauth2-autoconfigure两个依赖. </dependency& ...
 - 使用Identity Server 4建立Authorization Server (6) - js(angular5) 客户端
		
预备知识: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第二 ...
 - 使用Identity Server 4建立Authorization Server (4)
		
预备知识: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第二 ...
 - 每周开源项目分享-年轻人的第一个OAuth2.0 Server:hydra
		
年轻人的第一个OAuth2.0 Server:hydra hydra 是什么呢? OpenID Connect certified OAuth2 Server - cloud native, secu ...
 - Spring Cloud(6.3):搭建OAuth2 Resource Server
		
配置web.xml 添加spring-cloud-starter-security,spring-security-oauth2-autoconfigure2个依赖. <!-- Spring c ...
 - Spring Authorization Server 全新授权服务器整合使用
		
前言 Spring Authorization Server 是 Spring 团队最新开发适配 OAuth 协议的授权服务器项目,旨在替代原有的 Spring Security OAuth 经过半年 ...
 - Spring Authorization Server的使用
		
Spring Authorization Server的使用 一.背景 二.前置知识 三.需求 四.核心代码编写 1.引入授权服务器依赖 2.创建授权服务器用户 3.创建授权服务器和客户端 五.测试 ...
 - Spring Authorization Server 0.2.3发布,放出联合身份DEMO
		
很快啊Spring Authorization Server又发新版本了,现在的版本是0.2.3.本次都有什么改动呢?我们来了解一下. 0.2.3版本特性 本次更新的新特性不少. 为公开客户端提供默认 ...
 - Spring Authorization Server授权服务器入门
		
11月8日Spring官方已经强烈建议使用Spring Authorization Server替换已经过时的Spring Security OAuth2.0,距离Spring Security OA ...
 - Spring Authorization Server 实现授权中心
		
Spring Authorization Server 实现授权中心 源码地址 当前,Spring Security 对 OAuth 2.0 框架提供了全面的支持.Spring Authorizati ...
 
随机推荐
- FIFO设计
			
first in first out,先进先出 fifo是基于RAM进行设计的 双端口RAM设计(16*8) 如果大的RAM可以调用IP RAM的关键参数:深度和宽度 module dual_ram ...
 - JavaScript 对象和 JSON 的区别
			
参考原文:https://blog.csdn.net/jiaojiao772992/article/details/77871785/ 2.1 对象和 JSON 的区别 JSON 就是 JavaScr ...
 - Linux-定时任务-cron
 - [转帖]记录一则enq: TX - row lock contention的分析过程
			
https://www.cnblogs.com/jyzhao/p/8628184.html 故障描述:与客户沟通,初步确认故障范围大概是在上午的8:30-10:30之间,反应故障现象是Tomcat的连 ...
 - [转帖]create table INITRANS参数分析
			
https://www.modb.pro/db/44701 1. 内容介绍 Oracle数据库create table时使用INITRANS参数设置数据块ITL事务槽的数量,确保该数据块上 并发事务数 ...
 - [转帖]Rocksdb的优劣及应用场景分析
			
研究Rocksdb已经有七个月的时间了,这期间阅读了它的大部分代码,对底层存储引擎进行了适配,同时也做了大量的测试.在正式研究之前由于对其在本地存储引擎这个江湖地位的膜拜,把它想象的很完美,深入摸 ...
 - [转帖]TIDB-TIDB节点磁盘已满报警
			
一.背景 今日突然收到tidb节点的磁盘报警,磁盘容量已经超过了80%,但是tidb是不放数据的,磁盘怎么会满,这里就需要排查了 二.问题排查 解决步骤 1.df -h查看哪里占用磁盘比较多,然后通过 ...
 - [转帖]【MySQL 8】MySQL 5.7都即将停只维护了,是时候学习一波MySQL 8了!
			
https://juejin.cn/post/7111255789876019208 MySQL 8新特性 选择MySQL 8的背景:MySQL 5.6已经停止版本更新了,对于 MySQL 5.7 版 ...
 - lldb3.9.0 安装攻略
			
Study From https://github.com/dotnet/diagnostics/blob/master/documentation/lldb/centos7/build-instal ...
 - rfc7230 Message Syntax and Routing
			
rfc7230 目录 rfc7230 2 Architecture 2.6 Protocol Versioning 3 Message Format 3.1 Start Line 3.1.1 Requ ...