ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# Spring REST 自定义令牌认证示例 > 原文: [https://howtodoinjava.com/spring-restful/custom-token-auth-example/](https://howtodoinjava.com/spring-restful/custom-token-auth-example/) 通过使用 Spring REST 和 Spring Security 5 创建的方法,学习将 **基于自定义令牌的身份验证** 添加到 REST API。 将通过。 所有其他请求将返回`HTTP 403`响应。 ## 1\. Spring Security 依赖 包括以下依赖项以使用 Spring Security 类和接口。 `pom.xml` ```java <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.1.5.RELEASE</version> </dependency> ``` ## 2\. 扩展`AbstractPreAuthenticatedProcessingFilter` 创建一个类并扩展[`AbstractPreAuthenticatedProcessingFilter`](https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java)。 它是用于处理过滤器的基类,这些过滤器处理**预认证的**认证请求,其中假定主体已经由外部系统认证。 默认情况下,当身份验证尝试失败时,过滤器链将继续进行,以允许其他身份验证机制处理请求。 如果发现令牌无效,它将有助于将请求传递给其他安全过滤器(例如,表单登录名)。 `getPreAuthenticatedPrincipal()`方法有助于从当前请求中读取`auth`标头值。 `PreAuthTokenHeaderFilter.java` ```java import javax.servlet.http.HttpServletRequest; import org.springframework.security.web.authentication .preauth.AbstractPreAuthenticatedProcessingFilter; public class PreAuthTokenHeaderFilter extends AbstractPreAuthenticatedProcessingFilter { private String authHeaderName; public PreAuthTokenHeaderFilter(String authHeaderName) { this.authHeaderName = authHeaderName; } @Override protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { return request.getHeader(authHeaderName); } @Override protected Object getPreAuthenticatedCredentials(HttpServletRequest request) { return "N/A"; } } ``` 这是可选方法。 应用程序可能会决定立即简单地返回认证失败错误。 ## 3\. 配置`AuthenticationManager`并添加到`HttpSecurity` 我们需要设置身份验证管理器,它将处理身份验证过程并决定如何处理成功和失败方案。 添加身份验证管理器后,我们可以将`PreAuthTokenHeaderFilter`添加到`HttpSecurity`。 如果出现任何身份验证错误,则默认情况下将处理该错误[`ExceptionTranslationFilter`](https://docs.spring.io/spring-security/site/docs/4.2.11.RELEASE/apidocs/org/springframework/security/web/access/ExceptionTranslationFilter.html),该错误会在 Spring 转发到默认身份验证错误页面。 如果要以不同方式显示认证错误响应,则需要创建自定义`ExceptionTranslationFilter`类。 `AuthTokenSecurityConfig.java` ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; 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 org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; @Configuration @EnableWebSecurity @PropertySource("classpath:application.properties") @Order(1) public class AuthTokenSecurityConfig extends WebSecurityConfigurerAdapter { @Value("${howtodoinjava.http.auth.tokenName}") private String authHeaderName; //TODO: retrieve this token value from data source @Value("${howtodoinjava.http.auth.tokenValue}") private String authHeaderValue; @Override protected void configure(HttpSecurity httpSecurity) throws Exception { PreAuthTokenHeaderFilter filter = new PreAuthTokenHeaderFilter(authHeaderName); filter.setAuthenticationManager(new AuthenticationManager() { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String principal = (String) authentication.getPrincipal(); if (!authHeaderValue.equals(principal)) { throw new BadCredentialsException("The API key was not found " + "or not the expected value."); } authentication.setAuthenticated(true); return authentication; } }); httpSecurity. antMatcher("/api/**") .csrf() .disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilter(filter) .addFilterBefore(new ExceptionTranslationFilter( new Http403ForbiddenEntryPoint()), filter.getClass() ) .authorizeRequests() .anyRequest() .authenticated(); } } ``` ## 4\. 注册安全过滤器 传统上,spring security 在`DelegatingFilterProxy`基于 XML 的配置中以`web.xml`文件为起点。 `web.xml` ```java <!-- Spring Security --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 在 Java 配置中,我们可以通过删除类`AbstractSecurityWebApplicationInitializer`来实现相同的效果。 `SpringSecurityInitializer.java` ```java import org.springframework.security.web.context .AbstractSecurityWebApplicationInitializer; public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer { //no code needed } ``` ## 4\. Spring REST 自定义令牌认证演示 #### 4.1. 标头中没有身份验证令牌 `API 请求` ```java HTTP GET http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/ ``` `API 响应` ```java HTTP Status - 403 – Forbidden Type Status - Report Message Access - Denied Description - The server understood the request but refuses to authorize it. ``` #### 4.2. 标头中的身份验证令牌不正确 `API 请求` ```java HTTP GET http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/ AUTH_API_KEY: xyz123 ``` `API 响应` ```java HTTP Status - 403 – Forbidden Type Status - Report Message Access - Denied Description - The server understood the request but refuses to authorize it. ``` #### 4.2. 标头中的身份验证令牌有效 `API 请求` ```java HTTP GET http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/ AUTH_API_KEY: abcd123456 ``` `API 响应` ```java HTTP Status - 200 OK { //response body } ``` [下载源码](https://howtodoinjava.com/wp-content/downloads/SpringRestExample.zip) 学习愉快!