原文: 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

  1. <dependency>
  2. <groupId>org.springframework.security</groupId>
  3. <artifactId>spring-security-core</artifactId>
  4. <version>5.1.5.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.security</groupId>
  8. <artifactId>spring-security-config</artifactId>
  9. <version>5.1.5.RELEASE</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.security</groupId>
  13. <artifactId>spring-security-web</artifactId>
  14. <version>5.1.5.RELEASE</version>
  15. </dependency>

2. 扩展AbstractPreAuthenticatedProcessingFilter

创建一个类并扩展AbstractPreAuthenticatedProcessingFilter。 它是用于处理过滤器的基类,这些过滤器处理预认证的认证请求,其中假定主体已经由外部系统认证。

默认情况下,当身份验证尝试失败时,过滤器链将继续进行,以允许其他身份验证机制处理请求。 如果发现令牌无效,它将有助于将请求传递给其他安全过滤器(例如,表单登录名)。

getPreAuthenticatedPrincipal()方法有助于从当前请求中读取auth标头值。

PreAuthTokenHeaderFilter.java

  1. import javax.servlet.http.HttpServletRequest;
  2. import org.springframework.security.web.authentication
  3. .preauth.AbstractPreAuthenticatedProcessingFilter;
  4. public class PreAuthTokenHeaderFilter
  5. extends AbstractPreAuthenticatedProcessingFilter {
  6. private String authHeaderName;
  7. public PreAuthTokenHeaderFilter(String authHeaderName) {
  8. this.authHeaderName = authHeaderName;
  9. }
  10. @Override
  11. protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
  12. return request.getHeader(authHeaderName);
  13. }
  14. @Override
  15. protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
  16. return "N/A";
  17. }
  18. }

这是可选方法。 应用程序可能会决定立即简单地返回认证失败错误。

3. 配置AuthenticationManager并添加到HttpSecurity

我们需要设置身份验证管理器,它将处理身份验证过程并决定如何处理成功和失败方案。

添加身份验证管理器后,我们可以将PreAuthTokenHeaderFilter添加到HttpSecurity

如果出现任何身份验证错误,则默认情况下将处理该错误ExceptionTranslationFilter,该错误会在 Spring 转发到默认身份验证错误页面。 如果要以不同方式显示认证错误响应,则需要创建自定义ExceptionTranslationFilter类。

AuthTokenSecurityConfig.java

  1. import org.springframework.beans.factory.annotation.Value;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.context.annotation.PropertySource;
  4. import org.springframework.core.annotation.Order;
  5. import org.springframework.security.authentication.AuthenticationManager;
  6. import org.springframework.security.authentication.BadCredentialsException;
  7. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  9. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  10. import org.springframework.security.config.http.SessionCreationPolicy;
  11. import org.springframework.security.core.Authentication;
  12. import org.springframework.security.core.AuthenticationException;
  13. import org.springframework.security.web.access.ExceptionTranslationFilter;
  14. import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
  15. @Configuration
  16. @EnableWebSecurity
  17. @PropertySource("classpath:application.properties")
  18. @Order(1)
  19. public class AuthTokenSecurityConfig extends WebSecurityConfigurerAdapter {
  20. @Value("${howtodoinjava.http.auth.tokenName}")
  21. private String authHeaderName;
  22. //TODO: retrieve this token value from data source
  23. @Value("${howtodoinjava.http.auth.tokenValue}")
  24. private String authHeaderValue;
  25. @Override
  26. protected void configure(HttpSecurity httpSecurity) throws Exception
  27. {
  28. PreAuthTokenHeaderFilter filter = new PreAuthTokenHeaderFilter(authHeaderName);
  29. filter.setAuthenticationManager(new AuthenticationManager()
  30. {
  31. @Override
  32. public Authentication authenticate(Authentication authentication)
  33. throws AuthenticationException
  34. {
  35. String principal = (String) authentication.getPrincipal();
  36. if (!authHeaderValue.equals(principal))
  37. {
  38. throw new BadCredentialsException("The API key was not found "
  39. + "or not the expected value.");
  40. }
  41. authentication.setAuthenticated(true);
  42. return authentication;
  43. }
  44. });
  45. httpSecurity.
  46. antMatcher("/api/**")
  47. .csrf()
  48. .disable()
  49. .sessionManagement()
  50. .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  51. .and()
  52. .addFilter(filter)
  53. .addFilterBefore(new ExceptionTranslationFilter(
  54. new Http403ForbiddenEntryPoint()),
  55. filter.getClass()
  56. )
  57. .authorizeRequests()
  58. .anyRequest()
  59. .authenticated();
  60. }
  61. }

4. 注册安全过滤器

传统上,spring security 在DelegatingFilterProxy基于 XML 的配置中以web.xml文件为起点。

web.xml

  1. <!-- Spring Security -->
  2. <filter>
  3. <filter-name>springSecurityFilterChain</filter-name>
  4. <filter-class>org.springframework.web.filter.DelegatingFilterProxy
  5. </filter-class>
  6. </filter>
  7. <filter-mapping>
  8. <filter-name>springSecurityFilterChain</filter-name>
  9. <url-pattern>/*</url-pattern>
  10. </filter-mapping>

在 Java 配置中,我们可以通过删除类AbstractSecurityWebApplicationInitializer来实现相同的效果。

SpringSecurityInitializer.java

  1. import org.springframework.security.web.context
  2. .AbstractSecurityWebApplicationInitializer;
  3. public class SpringSecurityInitializer
  4. extends AbstractSecurityWebApplicationInitializer {
  5. //no code needed
  6. }

4. Spring REST 自定义令牌认证演示

4.1. 标头中没有身份验证令牌

API 请求

  1. HTTP GET http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/

API 响应

  1. HTTP Status - 403 Forbidden
  2. Type Status - Report
  3. Message Access - Denied
  4. Description - The server understood the request but refuses to authorize it.

4.2. 标头中的身份验证令牌不正确

API 请求

  1. HTTP GET http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/
  2. AUTH_API_KEY: xyz123

API 响应

  1. HTTP Status - 403 Forbidden
  2. Type Status - Report
  3. Message Access - Denied
  4. Description - The server understood the request but refuses to authorize it.

4.2. 标头中的身份验证令牌有效

API 请求

  1. HTTP GET http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/
  2. AUTH_API_KEY: abcd123456

API 响应

  1. HTTP Status - 200 OK
  2. {
  3. //response body
  4. }

下载源码

学习愉快!