1. Overview Spring Security 提供了不同的身份认证系统,例如通过数据库和 UserDetailService。
有时可能不想使用 JPA 持久层,而是想使用 MongoDB Repository。本文将带你了解如何使用 Spring Security 和 MongoDB 对用户进行认证。
2、Spring Security 使用 MongoDB 进行认证 MongoDB Repository 与 JPA Repository 类似不过,我们需要设置不同的配置。
2.1、Maven 依赖 本文使用嵌入式 MongoDB。首先,添加 spring-boot-starter-data-mongodb 和 de.flapdoodle.embed.mongo 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>de.flapdoodle.embed</groupId> <artifactId>de.flapdoodle.embed.mongo</artifactId> <version>3.3.1</version> </dependency> 2.2、配置 创建配置类:
@Configuration public class MongoConfig { private static final String CONNECTION_STRING = "mongodb://%s:%d"; private static final String HOST = "localhost"; @Bean public MongoTemplate mongoTemplate() throws Exception { int randomPort = SocketUtils.
1、概览 在使用 Spring Data MongoDB 时,可能需要比默认级别(INFO)更高的日志,以查看执行语句或查询参数等一些附加信息。
2、配置 MongoDB 查询日志 Spring Data MongoDB 通过 MongoOperations 接口或其主要的实现 MongoTemplate 来访问数据,因此只需为 MongoTemplate 类配置调 Debug 级别的日志即可。
与其他 Spring 或 Java 应用一样,可以使用日志库并为 MongoTemplate 定义日志级别。类似于如下:
<logger name="org.springframework.data.mongodb.core.MongoTemplate" level="DEBUG" /> 如果是 Spring Boot 应用,可以直接在 application.properties 文件中进行配置:
logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG 同样,也可以使用 YAML 文件:
logging: level: org: springframework: data: mongodb: core: MongoTemplate: DEBUG 3、日志测试类 创建一个 Book 类:
@Document(collection = "book") public class Book { @MongoId private ObjectId id; private String bookName; private String authorName; // getter 和 setter 方法 } 创建一个简单的测试类用于测试,并查看输出日志。
1、概览 本文将带你了解 Spring 6.1 中新添加的 JdbcClient 接口,它提供了 Fluent 风格的 API,统一了 JdbcTemplate 和 NamedParameterJdbcTemplate 的 Facade,支持链式操作。
有了 JdbcClient 后就可以使用 Fluent 风格的 API 定义查询、设置参数以及执行数据库操作了。
该功能简化了 JDBC 操作,使其更易读、更易懂。然而,对于 JDBC 批处理操作和存储过程的调用,仍然需要使用 JdbcTemplate 和 NamedParameterJdbcTemplate 类。
本文使用 H2 数据库来演示 JdbcClient 的功能。
2、数据库设置 创建 student 表:
CREATE TABLE student ( student_id INT AUTO_INCREMENT PRIMARY KEY, student_name VARCHAR(255) NOT NULL, age INT, grade INT NOT NULL, gender VARCHAR(10) NOT NULL, state VARCHAR(100) NOT NULL ); -- Student 1 INSERT INTO student (student_name, age, grade, gender, state) VALUES ('John Smith', 18, 3, 'Male', 'California'); -- Student 2 INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emily Johnson', 17, 2, 'Female', 'New York'); --More insert statements.
DataFieldMaxValueIncrementer 是 spring-jdbc 项目中的一个接口。用于在应用中生成连续、自增的序列。可用于 主键ID、订单号、流水号 等等。
它基于数据库实现,主要有 2 大子类。
AbstractSequenceMaxValueIncrementer:用于支持序列(SEQUENCE)的数据库(如 Oracle),使用标准的数据库序列。 AbstractColumnMaxValueIncrementer:用于不支持序列的数据库(如,MYSQL),使用一张表来模拟。 spring-jdbc 已经为当前流行的关系型数据库提供了具体的实现,类体系结构如下:
DataFieldMaxValueIncrementer |-AbstractDataFieldMaxValueIncrementer |-AbstractSequenceMaxValueIncrementer |-OracleSequenceMaxValueIncrementer # Oracle 数据库 |-PostgresSequenceMaxValueIncrementer # Postgres 数据库 |-SqlServerSequenceMaxValueIncrementer # SqlServer 数据库 |- ... # 还有一些其他的,这里忽略 |-AbstractColumnMaxValueIncrementer |-MySQLMaxValueIncrementer # MYSQL 数据库 DataFieldMaxValueIncrementer DataFieldMaxValueIncrementer 接口只有 3 个方法,很简单。
public interface DataFieldMaxValueIncrementer { int nextIntValue() throws DataAccessException; long nextLongValue() throws DataAccessException; String nextStringValue() throws DataAccessException; } nextIntValue:以 int 类型返回下一个序列。 nextLongValue:以 long 类型返回下一个序列。 nextStringValue:以 String 类型返回下一个序列。 使用 MySQLMaxValueIncrementer 本文以 MySQLMaxValueIncrementer 为例(毕竟 MYSQL 最流行)。
1、简介 本文将带你了解如何自定义从 JWT(JSON Web Token)Claim 到 Spring Security 权限(Authority)的映射。
2、背景 基于 Spring Security 的应用接收到请求时,它会经过一系列步骤,本质上旨在实现两个目标。
认证请求,以便应用知道谁在访问它 决定通过身份认证的请求是否可以执行相关操作 对于使用 JWT 的应用,授权方面包括:
从 JWT payload(通常是 scope 或 scp Claim)中提取 Claim 值 将这些 Claim 声明映射到一组 GrantedAuthority 对象中 一旦 Security 引擎设置了这些权限,它就可以评估是否有任何访问限制适用于当前请求,并决定是否可以继续处理。
3、默认的映射 在开箱即用的情况下,Spring 使用一种直接的策略将 Claim 声明转换为 GrantedAuthority 实例。首先,它会提取 scope 或 scp Claim,并将其拆分成一个字符串列表。接下来,它会为每个字符串创建一个新的 SimpleGrantedAuthority,使用前缀 SCOPE_,后跟 scope 值。
接下来,创建一个简单的端点来演示这个策略。看看 Authentication 实例有哪些关键属性。
@RestController @RequestMapping("/user") public class UserRestController { @GetMapping("/authorities") public Map<String,Object> getPrincipalInfo(JwtAuthenticationToken principal) { Collection<String> authorities = principal.getAuthorities() .
1. 问题 在浏览器中进行跨域请求一个接口时报错如下:
Access to XMLHttoRequest at ‘https://xxx.lzw.me/abc/getToken from origin “http://localhost:3001 has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Acess-Control-Allow-Origin’ header contains multiple values ‘*, *”. but only one is allowed.
2. 原因 从报错信息上理解,是 Acess-Control-Allow-Origin 的值为 *, *,设置了多个。从 nginx 配置上查看设置的值是 *。以非跨域的方式请求该接口,则可以在 Response 中看到 header 信息中包含了两个 Acess-Control-Allow-Origin 的设置。那么原因就是在 nginx 之外的其它网关或应用程序中还设置了该 header 值。找到它并移除个性化的设置逻辑即可。
3. 解决方法 如果 nginx 出口网关的设置是多余的,CORS 在应用程序层已有管理,则可以直接移除此处的配置。
如果是应用程序内部针对该接口添加了设置,考虑到需支持允许所有接口跨域访问,应修改应用程序移除相关逻辑。
如果希望在 nginx 层作统一配置管理,也可在应用程序出口网关层作 header 过滤。例如针对 Spring zuul 网关的设置实例:
1、Spring Bean 和 Java 堆内存 Java 堆是一个全局共享内存,应用中的所有运行线程都可以访问它。当 Spring 容器创建 Singleton Scope Bean 时,该 Bean 将存储在堆中。这样,所有并发线程都能指向同一个 Bean 实例。
2、如何处理并发请求? 举例来说,Spring 应用中有一个名为 ProductService 的单例 Bean:
@Service public class ProductService { private final static List<Product> productRepository = asList( new Product(1, "Product 1", new Stock(100)), new Product(2, "Product 2", new Stock(50)) ); public Optional<Product> getProductById(int id) { Optional<Product> product = productRepository.stream() .filter(p -> p.getId() == id) .findFirst(); String productName = product.map(Product::getName) .orElse(null); System.out.printf("Thread: %s; bean instance: %s; product id: %s has the name: %s%n", currentThread().
1、概览 在 Spring Cloud 中可以通过配置文件来启用、禁用服务发现,而不需要改动代码。
2、 设置 Eureka Server 和 Eureka Client 先创建一个 Eureka 服务器和一个 Discovery Client。
Eureka 服务创建过程,略!
2.1、Discovery Client 设置 创建 “Discovery Client” 应用,在 Eureka Server 上进行注册。
在 pom.xml 中添加 Web 和 Eureka Client starter 依赖:
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> 还需要在 dependencyManagement 中添加 spring-cloud-starter-parent 依赖,用于定义 cloud 组件的版本。
如果使用 Spring Initializr 创建项目,这些参数已经设置好了。如果没有,可以手动添加到 pom.xml 文件中:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-parent</artifactId> <version>${spring-cloud-dependencies.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <properties> <spring-cloud-dependencies.
1、简介 本文将带你了解 spring-boot-properties-migrator 模块,它是 Spring 为促进 Spring Boot 升级而提供的支持。用于帮助迁移 application properties。
随着每个 Spring Boot 版本的升级,可能会有一些属性被标记为已弃用、不再支持或新引入的属性。Spring 为每个升级发布了详细的 变更日志。然而,阅读这些变更日志可能会有些繁琐。这就该 spring-boot-properties-migrator 出场了,它通过为我们的设置提供个性化的信息来帮助我们进行属性迁移。
让我们来看看如何使用。
2、Demo 应用 把 Spring Boot 应用从 2.3.0 升级到 2.6.3。
2.1、Properties 在演示应用中,有两个 properties 文件。在默认 properties 文件 application.properties 中,添加如下配置:
spring.resources.cache.period=31536000 spring.resources.chain.compressed=false spring.resources.chain.html-application-cache=false dev Profile YAML 文件 application-dev.yaml:
spring: resources: cache: period: 31536000 chain: compressed: true html-application-cache: true properties 文件包含了几个在 Spring Boot 2.3.0 和 2.6.3 之间被替换或移除的属性。
同时提供了 .properties 和 .yaml 文件,以便更好地进行演示。
2.2、添加依赖 添加 spring-boot-properties-migrator 模块。
1、概览 本文通过一个示例来带你了解如何处理 Spring Security Resource Server 产生的 Spring Security 异常。
2、Spring Security Spring Security 是 Spring 的一个子项目。它试图将 Spring 项目中的所有用户访问控制功能进行整合。访问控制允许限制特定用户或角色在应用中可以执行的选项。
在本例中,我们重点关注 Exception Handler 的配置。Spring Security 提供了三种不同的接口来实现这一目的并控制产生的事件:
Authentication Success(认证成功)Handler Authentication Failure(认证失败)Handler Access Denied(拒绝访问)Handler 3、Security Configuration 首先,配置类必须创建一个 SecurityFilterChain Bean。它将负责管理应用的所有安全配置。因此,我们必须在这里引入 Handler。
定义所需的配置:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf() .disable() .httpBasic() .disable() .authorizeRequests() .antMatchers("/login") .permitAll() .antMatchers("/customError") .permitAll() .antMatchers("/access-denied") .permitAll() .antMatchers("/secured") .hasRole("ADMIN") .anyRequest() .authenticated() .and() .formLogin() .failureHandler(authenticationFailureHandler()) .successHandler(authenticationSuccessHandler()) .and() .exceptionHandling() .accessDeniedHandler(accessDeniedHandler()) .and() .logout(); return http.