基于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的更多相关文章

  1. Spring Cloud(6.1):搭建OAuth2 Authorization Server

    配置web.xml 添加spring-cloud-starter-security和spring-security-oauth2-autoconfigure两个依赖. </dependency& ...

  2. 使用Identity Server 4建立Authorization Server (6) - js(angular5) 客户端

    预备知识: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第二 ...

  3. 使用Identity Server 4建立Authorization Server (4)

    预备知识: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第二 ...

  4. 每周开源项目分享-年轻人的第一个OAuth2.0 Server:hydra

    年轻人的第一个OAuth2.0 Server:hydra hydra 是什么呢? OpenID Connect certified OAuth2 Server - cloud native, secu ...

  5. Spring Cloud(6.3):搭建OAuth2 Resource Server

    配置web.xml 添加spring-cloud-starter-security,spring-security-oauth2-autoconfigure2个依赖. <!-- Spring c ...

  6. Spring Authorization Server 全新授权服务器整合使用

    前言 Spring Authorization Server 是 Spring 团队最新开发适配 OAuth 协议的授权服务器项目,旨在替代原有的 Spring Security OAuth 经过半年 ...

  7. Spring Authorization Server的使用

    Spring Authorization Server的使用 一.背景 二.前置知识 三.需求 四.核心代码编写 1.引入授权服务器依赖 2.创建授权服务器用户 3.创建授权服务器和客户端 五.测试 ...

  8. Spring Authorization Server 0.2.3发布,放出联合身份DEMO

    很快啊Spring Authorization Server又发新版本了,现在的版本是0.2.3.本次都有什么改动呢?我们来了解一下. 0.2.3版本特性 本次更新的新特性不少. 为公开客户端提供默认 ...

  9. Spring Authorization Server授权服务器入门

    11月8日Spring官方已经强烈建议使用Spring Authorization Server替换已经过时的Spring Security OAuth2.0,距离Spring Security OA ...

  10. Spring Authorization Server 实现授权中心

    Spring Authorization Server 实现授权中心 源码地址 当前,Spring Security 对 OAuth 2.0 框架提供了全面的支持.Spring Authorizati ...

随机推荐

  1. 使用Amber计算单点能三步走

    技术背景 Amber是一个在分子动力学中非常常用的一个软件,可以用于进行分子动力学模拟计算,可以与一些软件配合进行增强采样.这里我们简单介绍一下如何使用Amber去计算一个分子构象的单点势能值,及其对 ...

  2. javase项目 正常导入jar 包

    1,在 java project 目录下新建 lib 文件夹 2,将 mysql 的 jar 包 复制到 新建的 lib 文件夹 3,选中 lib 下的 jar 包 , 右键点击选择 build pa ...

  3. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.20)

    百度网盘会员账号共享(11.20更新) 账号:zqv29268 密码:7003wayb 账号:rpz75364 密码:riyk1648 账号:0580quqn 密码:148hxhe 账号:132620 ...

  4. [转帖]shell编程之循环语句

    目录 一.循环语句 for循环 for语句的结构 嵌套循环 while语句的结构 while语句应用示例 until语句的结构 until语句示例 二.跳出循环 continue跳出循环 break跳 ...

  5. [转帖]OpenSSL版本历史

    OpenSSL版本历史 新闻日志 这是所有 OpenSSL 公告的简洁日志.它们几乎是发布通知. 日期物品 2021 年 7 月 29 日OpenSSL 3.0 的 Beta 2 现已推出.这是一个候 ...

  6. [转帖]通过拓扑 label 进行副本调度

    https://docs.pingcap.com/zh/tidb/stable/schedule-replicas-by-topology-labels#%E5%9F%BA%E4%BA%8E%E6%8 ...

  7. [转帖]Kafka-Kraft 模式架构部署

    news文章来源: Kafka-Kraft 模式架构部署 Kafka网址:https://kafka.apache.org/ PS:因环境原因此文档内端口都有修改! 1.去官网下载二进制包 PS:3. ...

  8. [转帖]Centos 7 查看磁盘io ,找出占用io读写很高的进程

    1,先用iostat查看磁盘io 是否读写负载很高 用iostat -x 1 10 如果 iostat 没有,要 yum install sysstat安装这个包,第一眼看下图红色圈圈的那个如果%ut ...

  9. [转帖]Linux性能优化(十五)——CPU绑定

    一.孤立CPU 1.孤立CPU简介 针对CPU密集型的任务,CPU负载较高,推荐设置CPU Affinity,以提高任务执行效率,避免CPU进行上下文切换,提高CPU Cache命中率. 默认情况下, ...

  10. 45从零开始用Rust编写nginx,静态文件服务器竟然还有这些细节

    wmproxy wmproxy已用Rust实现http/https代理,socks5代理, websocket代理,反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透等,力争打 ...