这是我的Spring Boot Blog帖子系列的第三篇文章。 在第一篇文章中,我谈到了我使用Spring Boot创建RESTFul Services的经验。 然后我将样本扩展到
与Swagger文档集成 。 在这篇文章中,我将在安全方面扩展上述示例。
什么是API安全性
API安全性广泛,具有许多不同的定义,含义和解决方案。 API安全性中的主要关键术语是授权,身份验证,加密,联合和委派。 但是,在这里我不会谈论它们。
什么是认证
身份验证用于可靠地确定最终用户的身份,并根据正确标识的用户授予对资源的访问权限。
什么是基本身份验证
基本身份验证是对资源实施访问控制的最简单方法。 在此,HTTP用户代理在发出请求时提供用户名和密码。 当需要身份验证时,包含用户名和密码的字符串由冒号分隔,并在发送到后端之前经过Base64编码。
如何调用基本身份验证受保护的API
选项1:发送授权标头。 该值是base64编码的username:password Ex:“授权:基本Y2hhbmRhbmE6Y2hhbmRhbmE =”
curl -X GET http://localhost:8080/admin/hello/chandana -H 'authorization: Basic Y2hhbmRhbmE6Y2hhbmRhbmE='
选项2:使用网址:
curl -X GET -u username:password http://localhost:8080/admin/hello/chandana
好的,我们讨论了一些基本的东西。 因此,让我们来看一下如何使用Spring Security保护REST API。 您可以从我的GitHub存储库下载初始示例代码(Swagger Spring Boot Project源代码)
为了使用基本的auth安全性增强我们先前的示例,首先我将在pom文件中添加“ spring-boot-starter-security”和“ spring-boot-starter-tomcat”依赖项。
<!-- -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
下一步是使用@EnableWebSecurity批注对我们的配置类进行批注,并从WebSecurityConfigurerAdapter扩展配置类。 EnableWebSecurity批注将启用Spring-Security Web安全支持。
@Configuration
@EnableSwagger2
@EnableWebSecurity
public class ApplicationConfig extends WebSecurityConfigurerAdapter {
重写的configure(HttpSecurity)方法用于定义哪些URL路径应该受到保护,哪些不应该受到保护。 在我的示例中,不需要“ /”和“ / api”路径进行任何身份验证,并且任何其他路径(例如:“ admin”)都应使用基本身份验证进行身份验证。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/", "/api/**").permitAll()
.anyRequest().authenticated();
http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint);
}
在configureGlobal(AuthenticationManagerBuilder)方法中,我创建了一个内存用户存储,其中包含一个名为“ chandana”的用户。 在那里,我为内存中的用户添加了用户名,密码和userole。
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("chandana").password("chandana").roles("USER");
}
除此之外,您还可以看到我已将自动装配的BasicAuthenticationPoint添加到我的配置类中。 BasicAuthenticationEntryPoint类的目的是将“ WWW-Authenticate”标头设置为响应。 因此,Web浏览器将显示一个对话框,用于基于基本身份验证机制(WWW-Authenticate标头)输入用户名和密码
然后,您可以使用“ mvn spring-boot:run”运行示例。 当您访问“ localhost:8080 / api / hello / chandana”时,调用api不需要基本身份验证。 但是,如果您尝试访问“ localhost:8080 / admin / hello / chandana”,则需要提供基本的身份验证凭据才能访问资源。
AppConfig类:
package com.chandana.helloworld.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@EnableWebSecurity
public class ApplicationConfig extends WebSecurityConfigurerAdapter {
@Autowired
private BasicAuthenticationPoint basicAuthenticationPoint;
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.chandana.helloworld.controllers"))
.paths(PathSelectors.any())
.build();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/", "/api/**").permitAll()
.anyRequest().authenticated();
http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint);
}
private ApiInfo getApiInfo() {
Contact contact = new Contact("Chandana Napagoda", "http://blog.napagoda.com", "cnapagoda@gmail.com");
return new ApiInfoBuilder()
.title("Example Api Title")
.description("Example Api Definition")
.version("1.0.0")
.license("Apache 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0")
.contact(contact)
.build();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("chandana").password("chandana").roles("USER");
}
}
BasicAuthenticationEntryPoint类:
package com.chandana.helloworld.config;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class BasicAuthenticationPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=" +getRealmName());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 - " + authEx.getMessage());
}
@Override
public void afterPropertiesSet() throws Exception {
setRealmName("Chandana");
super.afterPropertiesSet();
}
}
翻译自: https://www.javacodegeeks.com/2017/10/secure-spring-boot-rest-api-using-basic-authentication.html