用API Key保护Spring Boot 接口的安全

news/2024/10/18 22:33:18/

1、概述

     安全性在REST API开发中扮演着重要的角色。一个不安全的REST API可以直接访问到后台系统中的敏感数据。因此,企业组织需要关注API安全性。

        Spring Security 提供了各种机制来保护我们的 REST API。其中之一是 API 密钥。API 密钥是客户端在调用 API 调用时提供的令牌。

       在本教程中,我们将讨论如何在Spring Security中实现基于API密钥的身份验证。

2、REST API Security

       Spring Security可以用来保护REST API的安全性。REST API是无状态的,因此不应该使用会话或cookie。相反,应该使用Basic authentication,API Keys,JWT或OAuth2-based tokens来确保其安全性。

2.1. Basic Authentication

      Basic authentication是一种简单的认证方案。客户端发送HTTP请求,其中包含Authorization标头的值为Basic base64_url编码的用户名:密码。Basic authentication仅在HTTPS / SSL等其他安全机制下才被认为是安全的。

2.2. OAuth2

     OAuth2是REST API安全的行业标准。它是一种开放的认证和授权标准,允许资源所有者通过访问令牌将授权委托给客户端,以获得对私有数据的访问权限。

2.3. API Keys

      一些REST API使用API密钥进行身份验证。API密钥是一个标记,用于向API客户端标识API,而无需引用实际用户。标记可以作为查询字符串或在请求头中发送。

3、用API Keys保护REST API

3.1  添加Maven 依赖

      让我们首先在我们的pom.xml中声明spring-boot-starter-security依赖关系:


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

3.2 创建自定义过滤器(Filter)

实现思路是从请求头中获取API Key,然后使用我们的配置检查秘钥。在这种情况下,我们需要在Spring Security 配置类中添加一个自定义的Filter。

我们将从实现GenericFilterBean开始。GenericFilterBean是一个基于javax.servlet.Filter接口的简单Spring实现。

让我们创建AuthenticationFilter类:


public class AuthenticationFilter extends GenericFilterBean {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws IOException, ServletException {try {Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request);SecurityContextHolder.getContext().setAuthentication(authentication);} catch (Exception exp) {HttpServletResponse httpResponse = (HttpServletResponse) response;httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);PrintWriter writer = httpResponse.getWriter();writer.print(exp.getMessage());writer.flush();writer.close();}filterChain.doFilter(request, response);}
}

我们只需要实现doFilter()方法,在这个方法中我们从请求头中获取API Key,并将生成的Authentication对象设置到当前的SecurityContext实例中。

然后请求被传递给其余的过滤器处理,接着转发给DispatcherServlet最后到达我们的控制器。

AuthenticationService类中,实现从Header中获取API Key并构造Authentication对象,代码如下:


public class AuthenticationService {private static final String AUTH_TOKEN_HEADER_NAME = "X-API-KEY";private static final String AUTH_TOKEN = "Baeldung";public static Authentication getAuthentication(HttpServletRequest request) {String apiKey = request.getHeader(AUTH_TOKEN_HEADER_NAME);if ((apiKey == null) || !apiKey.equals(AUTH_TOKEN)) {throw new BadCredentialsException("Invalid API Key");}return new ApiKeyAuthentication(apiKey, AuthorityUtils.NO_AUTHORITIES);}
}

在这里,我们检查请求头是否包含 API Key,如果为空 或者Key值不等于密钥,那么就抛出一个 BadCredentialsException。如果请求头包含 API Key,并且验证通过,则将密钥添加到安全上下文中,然后调用下一个安全过滤器。getAuthentication 方法非常简单,我们只是比较 API Key 头部和密钥是否相等。

为了构建 Authentication 对象,我们必须使用 Spring Security 为了标准身份验证而构建对象时使用的相同方法。所以,需要扩展 AbstractAuthenticationToken 类并手动触发身份验证。

3.3. 扩展AbstractAuthenticationToken

为了成功地实现我们应用的身份验证功能,我们需要将传入的API Key转换为AbstractAuthenticationToken类型的身份验证对象。AbstractAuthenticationToken类实现了Authentication接口,表示一个认证请求的主体和认证信息。

让我们创建ApiKeyAuthentication类:


public class ApiKeyAuthentication extends AbstractAuthenticationToken {private final String apiKey;public ApiKeyAuthentication(String apiKey,Collection<?extends GrantedAuthority> authorities) {super(authorities);this.apiKey = apiKey;setAuthenticated(true);}@Overridepublic Object getCredentials() {return null;}@Overridepublic Object getPrincipal() {return apiKey;}
}

ApiKeyAuthentication 类是类型为 AbstractAuthenticationToken 的对象,其中包含从 HTTP 请求中获取的 apiKey 信息。在构造方法中使用 setAuthenticated(true) 方法。因此,Authentication对象包含 apiKey 和authenticated字段:

3.4. Security Config

通过创建建一个SecurityFilterChain bean,可以通过编程方式把我们上面编写的自定义过滤器(Filter)进行注册。

我们需要在 HttpSecurity 实例上使用 addFilterBefore() 方法在 UsernamePasswordAuthenticationFilter 类之前添加 AuthenticationFilter

创建SecurityConfig 类:


@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/**").authenticated().and().httpBasic().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);return http.build();}}
 

此外注意代码中我们吧绘画策略(session policy)设置为无状态(STATELESS),因为我们使用的是REST。

3.5. ResourceController

最后,我们创建ResourceController,实现一个Get请求  /home


@RestController
public class ResourceController {@GetMapping("/home")public String homeEndpoint() {return "Baeldung !";}
}

3.6. 禁用 Auto-Configuration


@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
public class ApiKeySecretAuthApplication {public static void main(String[] args) {SpringApplication.run(ApiKeySecretAuthApplication.class, args);}
}
 

4. 测试

我们先不提供API Key进行测试

curl --location --request GET 'http://localhost:8080/home'

返回 401 未经授权错误

请求头中加上API Key后,再次请求

curl --location --request GET 'http://localhost:8080/home' \
--header 'X-API-KEY: Baeldung'

请求返回状态200

代码:https://github.com/eugenp/tutorials/tree/master/spring-security-modules/spring-security-web-boot-4

 


http://www.ppmy.cn/news/581880.html

相关文章

2022哪款蓝牙耳机性价比高?高品质蓝牙耳机测评

在蓝牙耳机的横空出世的时候&#xff0c;受到很多年轻人的追捧&#xff0c;各大网络都上新了蓝牙耳机&#xff0c;因为蓝牙耳机在现在的社会生活中必不可少。下面小编为大家整理的蓝牙耳机好评榜&#xff0c;推荐几款小编觉得品质比较高的几款耳机吧&#xff01; 第一款&#…

哪家蓝牙耳机性价比高?总结知乎力荐的这五款蓝牙耳机

如今蓝牙技术的火速发展&#xff0c;也产生了不少音质好、质量佳的耳机品牌&#xff0c;喜欢音乐的小伙伴经常陶醉于声音带来的美感当中。对于蓝牙耳机的要求除了音质&#xff0c;一些新的功能也会提高耳机使用带来的满足感&#xff0c;比如主动降噪&#xff0c;比如语音控制等…

力扣日记1401

1. 题目 LeetCode 1401. 圆和矩形是否有重叠 1.1 题意 给定圆和矩形&#xff0c;判断两个图形是否有重叠部分 1.2 分析 两个图形重叠有两种情况&#xff0c;相交和包含。 先考虑相交&#xff1a;相交的话圆至少和矩形的某条边有交点&#xff0c;因为矩形四条边都平行/重合于…

Mysql之回表

文章目录 什么是回表为什么会回表怎么避免回表 什么是回表 当需要查询的数据在索引树中不存在的时候&#xff0c;需要再次到聚集索引中去获取&#xff0c;这个过程就叫回表。 更简单点就是&#xff1a;先定位主键值&#xff0c;再定位行纪录。 那什么是聚集索引呢&#xff1…

SSM山西能源学院教室管理系统-计算机毕设 附源码81671

SSM山西能源学院教室管理系统 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;山西能源学院教室管理系统当然也不能排除在外。山西能源学院教室管理系统是以实际运用为…

股票量化分析工具QTYX使用攻略——涨停个股挖掘热门板块(更新2.6.6)

搭建自己的量化系统 如果要长期在市场中立于不败之地&#xff01;必须要形成一套自己的交易系统。 行情不等人&#xff01;边学习边实战&#xff0c;在实战中学习才是最有效地方式。于是我们分享一个即可以用于学习&#xff0c;也可以用于实战炒股分析的量化系统——QTYX。 QTY…

Axure教程—中继器筛查与排序

当工作中需要进行数据筛查排序操作时&#xff0c;我们可以如何使用Axure来进行相关操作呢&#xff1f;本篇文章里&#xff0c;作者利用中继器为我们展示了数据筛查与排序&#xff0c;让我们一起来看一下。 预览效果 预览地址&#xff1a;https://6q6ajh.axshare.com 功能介绍…

【OpenCV】Python广角摄像头的畸变矫正

效果图 三幅图像分别为矫正前、校正后和裁减后的图片。 矫正后的图像有些奇怪&#xff0c;需要把无用的部分裁剪掉。 代码 步骤一&#xff1a;拍摄棋盘图片 运行该程序&#xff0c;按空格键拍摄棋盘信息&#xff08;注意拍摄的棋盘要完整&#xff09;&#xff0c;拍摄20张…