Spring Security原理和实战
Web服务提供者的安全访问无疑是十分重要的,而SpringSecurity安全模块是保护Web应用的一个非常好的选择。
Spring Security是Spring应用项目中的一个安全模块,特别是在Spring Boot项目中,Spring Security默认为自动开启,可见其重要性。
在微服务架构下,建议仅将Spring Security组件应用于网关(如Zuul),对于集群内部的微服务提供者,不建议启用Spring Security组件,因为重复的验证会降低请求处理的性能。本文配套的crazyspringcloud微服务脚手架就是这样做的。
如果需要为微服务提供者关闭Spring Security组件的自动启动,那么可以在启动类上添加以下注解:
@EnableEurekaClient
@SpringBootApplication(scanBasePackages = {
...
}, exclude = {SecurityAutoConfiguration.class})
或者可以在应用配置文件中将它的自动配置类排除,具体代码如下:
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.servlet.
SecurityAutoConfiguration
6.4.1 Spring Security核心组件
Spring Security核心组件有Authentication(认证/身份验证)、AuthenticationProvider(认证提供者)、AuthenticationManager(认证管理者)等。下面分别介绍。
1.Spring Security核心组件之Authentication
Authentication直译是“认证”的意思,在Spring Security中,Authentication接口用来表示凭证或者令牌,可以理解为用户的用户名、密码、权限等信息。Authentication的代码如下:
public interface Authentication extends Principal, Serializable {
//权限集合
//可使用AuthorityUtils.commaSeparatedStringToAuthorityList
("admin, ROLE_ADMIN")进行初始化
Collection<? extends GrantedAuthority> getAuthorities();
//用户名和密码认证时,可以理解为密码
Object getCredentials();
//认证时包含的一些详细信息,可以是一个包含用户信息的POJO实例
Object getDetails();
//用户名和密码认证时,可以理解为用户名
Object getPrincipal();
//是否认证通过,通过为true
boolean isAuthenticated();
//设置是否认证通过
void setAuthenticated(boolean isAuthenticated)
throws IllegalArgumentException;
}
下面对Authentication的方法进行说明,具体如下:
(1)getPrincipal方法:Principal直译为“主要演员、主角”,用于获取用户身份信息,可以是用户名,也可以是用户的ID等,具体的值需要依据具体的认证令牌实现类确定。
(2)getAuthorities方法:用于获取用户权限集合,一般情况下获取到的是用户的权限信息。
(3)getCredentials方法:直译为获取资格证书。用户名和密码认证时,通常情况下获取到的是密码信息。
(4)getDetails方法:用于获取用户的详细信息。用户名和密码认证时,这部分信息可以是用户的POJO实例。
(5)isAuthenticated方法:判断当前Authentication凭证是否已验证通过。
(6)setAuthenticated方法:设置当前Authentication凭证是否已验证通过(true或false)。
在Spring Security中,Authentication认证接口有很多内置的实现类,下面举例说明。
(1)
UsernamePasswordAuthenticationToken:用于在用户名+密码认证的场景中作为验证的凭证,该凭证(令牌)包含用户名+密码信息。
(2)
RememberMeAuthenticationToken:用于“记住我”的身份认证场景。如果用户名+密码成功认证之后,在一定时间内不需要再输入用户名和密码进行身份认证,就可以使用RememberMeAuthenticationToken凭证。通常是通过服务端发送一个Cookie给客户端浏览器,下次浏览器再访问服务端时,服务端能够自动检测客户端的Cookie,根据Cookie值自动触发RememberMeAuthenticationToken凭证/令牌的认证操作。
(3)
AnonymousAuthenticationToken:对于匿名访问的用户,Spring Security支持为其建立一个AnonymousAuthenticationToken匿名凭证实例存放在SecurityContextHolder中。
除了以上内置凭证类外,还可以通过实现Authentication定制自己的身份认证实现类。
2.Spring Security核心组件之AuthenticationProvider
AuthenticationProvider是一个接口,包含两个函数authenticate和supports,用于完成对凭证进行身份认证操作。
public interface AuthenticationProvider {
//对实参authentication进行身份认证操作
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
//判断是否支持该authentication
boolean supports(Class<?> authentication);
}
AuthenticationProvider接口的两个方法说明如下:
(1)authenticate方法:表示认证的操作,对authentication参数对象进行身份认证操作。如果认证通过,就返回一个认证通过的凭证/令牌。通过源码中的注释可以知道,如果认证失败,就抛出异常。
(2)supports方法:判断实参authentication是否为当前认证提供者所能认证的令牌。
在Spring Security中,AuthenticationProvider接口有很多内置的实现类,下面举例说明。
(1)
AbstractUserDetailsAuthenticationProvider:这是一个对UsernamePasswordAuthentication Token类型的凭证/令牌进行验证的认证提供者类,用于“用户名+密码”验证的场景。
(2)
RememberMeAuthenticationProvider:这是一个对
RememberMeAuthenticationToken类型的凭证/令牌进行验证的认证提供者类,用于
“记住我”的身份认证场景。
(3)
AnonymousAuthenticationProvider:这是一个对AnonymousAuthenticationToken类型的凭证/令牌进行验证的认证提供者类,用于匿名身份认证场景。
此外,如果自定义了凭证/令牌,并且Spring Security的默认认证提供者类不支持该凭证/令牌,就可以通过实现AuthenticationProvider接口来扩展出自定义的认证提供者。
3.Spring Security核心组件之AuthenticationManager
AuthenticationManager是一个接口,其唯一的authenticate验证方法是认证流
程的入口,接收一个Authentication令牌对象作为参数。
public interface AuthenticationManager {
//认证流程的入口
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}AuthenticationManager的一个实现类名为ProviderManager,该类有一个
providers成员变量,负责管理一个提供者清单列表,其源码如下:
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
...
//提供者清单
private List<AuthenticationProvider> providers = Collections.emptyList();
//迭代提供者清单,找出支持令牌的提供者,交给提供者去执行令牌验证
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
...
}
}
认证管理者ProviderManager在进行令牌验证时,会对提供者列表进行迭代,找出支持令牌的认证提供者,并交给认证提供者去执行令牌验证。如果该认证提供者的supports方法返回true,就会调用该提供者的authenticate方法。如果验证成功,那么整个认证过程结束;如果不成功,那么继续处理列表中的下一个提供者。只要有一个验证成功,就会认证成功。
6.4.2 Spring Security的请求认证处理流程
一个基础、简单的Spring Security请求认证的处理流程大致包括以下步骤:
(1)定制一个凭证/令牌类。
(2)定制一个认证提供者类和凭证/令牌类进行配套,并完成对自制凭证/令牌实例的验证。
(3)定制一个过滤器类,从请求中获取用户信息组装成定制凭证/令牌,交给认证管理者。
(4)定制一个HTTP的安全认证配置类(AbstractHttpConfigurer子类),将上一步定制的过滤器加入请求的过滤处理责任链。
(5)定义一个Spring Security安全配置类(
WebSecurityConfigurerAdapter子类),对Web容器的HTTP安全认证机制进行配置。
为了演示,这里实现一个非常简单的认证处理流程,具体的功能如下:
当系统资源被访问时,过滤器从HTTP的token请求头获取用户名和密码,然后与系统中的用户信息进行匹配,如果匹配成功,就可以访问系统资源,否则返回403响应码,表示未授权。演示程序的代码位于本书配套源码的demo-provider模块中。
演示程序的第一步:定制一个凭证/令牌类,封装用户的用户名和密码。所定制的DemoToken令牌的代码如下:
package com.crazymaker.springcloud.demo.security;
//省略import
public class DemoToken extends AbstractAuthenticationToken
{
//用户名称
private String userName;
//密码
private String password;
...
}
演示程序的第二步:定制一个认证提供者类和凭证/令牌类进行配套,并完成对自制凭证/令牌实例的验证。所定制的DemoAuthProvider类的代码如下:
public class DemoAuthProvider implements AuthenticationProvider
{
public DemoAuthProvider()
{
}
//模拟的数据源,实际场景从DB中获取
private Map<String, String> map = new LinkedHashMap<>();
//初始化模拟的数据源,放入两个用户
{
map.put("zhangsan", "123456" );
map.put("lisi", "123456" );
}
//具体的验证令牌方法
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
DemoToken token = (DemoToken) authentication;
//从数据源map中获取用户密码
String rawPass = map.get(token.getUserName());
//验证密码,如果不相等,就抛出异常
if (!token.getPassword().equals(rawPass))
{
token.setAuthenticated(false);
throw new BadCredentialsException("认证有误:令牌校验失败" );
}
//验证成功
token.setAuthenticated(true);
return token;
}
/**
*判断令牌是否被支持
*@param authentication 这里仅仅DemoToken令牌被支持
*@return
*/
@Override
public boolean supports(Class<?> authentication)
{
return authentication.isAssignableFrom(DemoToken.class);
}
}
DemoAuthProvider模拟了一个简单的数据源并且加载了两个用户。在其authenticate验证方法中,将入参DemoToken令牌中的用户名和密码与模拟数据源中的用户信息进行匹配,若匹配成功,则验证成功。
演示程序的第三步:定制一个过滤器类,从请求中获取用户信息并组装成定制凭证/令牌,交给认证管理者。在生产场景中,认证信息一般为某个HTTP头部信息(如Cookie信息、Token信息等)。本演示程序中的过滤器类为DemoAuthFilter,从请求头中获取token字段,解析之后组装成DemoToken令牌实例,提交给AuthenticationManager进行验证。DemoAuthFilter的代码如下:
public class DemoAuthFilter extends OncePerRequestFilter
{
//认证失败的处理器
private AuthenticationFailureHandler failureHandler = new AuthFailureHandler();
...
//authenticationManager是认证流程的入口,接收一个Authentication令牌对象作为参数 private AuthenticationManager authenticationManager;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
{
...
AuthenticationException failed = null;
try
{
Authentication returnToken=null;
boolean succeed=false;
//从请求头中获取认证信息
String token = request.getHeader
(SessionConstants.AUTHORIZATION_HEAD);
String[] parts = token.split("," );
//组装令牌
DemoToken demoToken = new DemoToken(parts[0],parts[1]);
//提交给AuthenticationManager进行令牌验证
returnToken = (DemoToken) this.getAuthenticationManager()
.authenticate(demoToken);
//获取认证成功标志
succeed=demoToken.isAuthenticated();
if (succeed)
{
//认证成功,设置上下文令牌
SecurityContextHolder.getContext().setAuthentication
(returnToken);
//执行后续的操作
filterChain.doFilter(request, response);
return;
}
} catch (Exception e)
{
logger.error("认证有误", e);
failed = new AuthenticationServiceException("请求头认证消息格式错误",e );
}
if(failed == null)
{
failed = new AuthenticationServiceException("认证失败");
}
//认证失败了
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, failed);
}
...
}
为了使得过滤器能够生效,必须将过滤器加入Web容器的HTTP过滤处理责任链,此项工作可以通过实现一个AbstractHttpConfigurer配置类来完成。
演示程序的第四步:定制一个HTTP的安全认证配置类(AbstractHttpConfigurer子类),将上一步定制的过滤器加入请求的过滤处理责任链。定制的DemoAuthConfigurer代码如下:
public class DemoAuthConfigurer<T extends DemoAuthConfigurer<T, B>, B
extends HttpSecurityBuilder<B>> extends AbstractHttpConfigurer<T, B>
{
//创建认证过滤器
private DemoAuthFilter authFilter = new DemoAuthFilter();
//将过滤器加入http过滤处理责任链
@Override
public void configure(B http) throws Exception
{
//获取Spring Security共享的AuthenticationManager认证管理者实例
将其设置到认证过滤器 //将其设置到认证过滤器
authFilter.setAuthenticationManager(http.getSharedObject
(AuthenticationManager.class));
DemoAuthFilter filter = postProcess(authFilter);
//将过滤器加入http过滤处理责任链
http.addFilterBefore(filter, LogoutFilter.class);
}
}
演示程序的第五步:定义一个Spring Security安全配置类(
WebSecurityConfigurerAdapter子类),对Web容器的HTTP安全认证机制进行配置。这一步有两项工作:一是应用DemoAuthConfigurer配置类;二是构造AuthenticationManagerBuilder认证管理者实例。定制类DemoWebSecurityConfig的代码如下:
@EnableWebSecurity
public class DemoWebSecurityConfig extends WebSecurityConfigurerAdapter
{
//配置HTTP请求的安全策略,应用DemoAuthConfigurer配置类实例
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
...
.and()
//应用DemoAuthConfigurer配置类
.apply(new DemoAuthConfigurer<>())
.and()
.sessionManagement().disable();
}
//配置认证Builder,由其负责构造AuthenticationManager认证管理者实例
//Builder将构造AuthenticationManager实例,并且作为HTTP请求的共享对象存储
//在代码中可以通过http.getSharedObject(AuthenticationManager.class) 来获取管理者实例
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
//加入自定义的Provider认证提供者实例
auth.authenticationProvider(demoAuthProvider());
}
//自定义的认证提供者实例
@Bean("demoAuthProvider" )
protected DemoAuthProvider demoAuthProvider()
{
return new DemoAuthProvider();
}
}
如何对以上自定义的安全认证机制进行验证呢?首先启动demo-provider服务,然后在浏览器中访问其swagge-ui界面,如图6-4所示。
图6-4 demo-provider服务的swagge-ui界面
然后在swagger-ui界面访问/api/demo/hello/v1,发现认证失败,如图6-5所示。
图6-5 直接访问/api/demo/hello/v1返回认证失败
这是由于前面所定义的Spring Security的请求认证处理流程已经生效。接下来在swagger-ui界面再一次访问/api/demo/hello/v1,不过这一次给token请求头输入了正确的用户名和密码,如图6-6所示。
图6-6 给token请求头输入了正确的用户名和密码
最后,再一次访问/api/demo/hello/v1,发现请求的返回值已经正常,表明前面所定义的Spring Security的请求认证处理流程起到了对请求进行用户名和密码验证的作用。
6.4.3 基于数据源的认证流程
在大多数生产场景中,用户信息都存储在某个数据源(如数据库)中,认证过程中涉及从数据源加载用户信息的环节。Spring Security为这种场景内置了一套解决方案,主要涉及几个内置类。
1.UsernamePasswordAuthenticationToken
此认证类实现了Authentication接口,主要封装用户输入的用户名和密码信息,提供给支持的认证提供者进行认证。
2.AbstractUserDetailsAuthenticationProvider
此认证提供者类与
UsernamePasswordAuthenticationToken凭证/令牌类配套,但这是一个抽象类,具体的验证逻辑需要由子类完成。
此认证提供者类的常用子类为DaoAuthenticationProvider类,该类依赖一个UserDetailsService用户服务数据源,用于获取UserDetails用户信息,其中包括用户名、密码和所拥有的权限等。此认证提供者子类从数据源UserDetailsService中加载用户信息后,将待认证的令牌中的“用户名+密码”信息和所加载的数据源用户信息进行匹配和验证。
3.UserDetailsService
UserDetailsService有一个loadUserByUsername方法,其作用是根据用户名从数据源中查询用户实体。一般情况下,可以实现一个定制的UserDetailsService接口的实现类来从特定的数据源获取用户信息。用户信息服务接口的源码如下:
public interface UserDetailsService {
//通过用户名从数据源加载用户信息
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
4.UserDetails
UserDetails是一个接口,主要封装用户名、密码、是否过期、是否可用等信息。此接口的源码如下:
public interface UserDetails extends Serializable {
//权限集合
Collection<? extends GrantedAuthority> getAuthorities();
//密码,一般为密文
String getPassword();
//用户名
String getUsername();
//用户名是否未过期
boolean isAccountNonExpired();
//用户名是否未锁定
boolean isAccountNonLocked();
//用户密码是否未过期
boolean isCredentialsNonExpired();
//账号是否可用(可理解为是否删除)
boolean isEnabled();
}
UserDetails接口的密码属性和
UsernamePasswordAuthenticationToken的密码属性的区别在于:前者的密码来自数据源,是密文;后者的密码来自用户请求,是明文。明文和密文的匹配工作由PasswordEncoder加密器完成。
5.PasswordEncoder
PasswordEncoder是一个负责明文加密、判断明文和密文匹配的接口,源码如下:
public interface PasswordEncoder {
//对明文rawPassword加密
String encode(CharSequence rawPassword);
//判断rawPassword与encodedPassword是否匹配
boolean matches(CharSequence rawPassword, String encodedPassword);
}
DaoAuthenticationProvider提供者在验证之前会通过内部的PasswordEncoder加密器实例对令牌中的密码明文和UserDetails中的密码密文进行匹配。若匹配不成功,则令牌验证不通过。
PasswordEncoder的内置实现类有多个,如BCryptPasswordEncoder、Pbkdf2PasswordEncoder等。其中BCryptPasswordEncoder比较常用,其采用SHA-256+密钥+盐的组合方式对密码明文进行Hash编码处理。注意,SHA-256是Hash编码算法,不是加密算法。这里是对明文编码而不是加密,这是因为加密算法往往可以解密,只是解密的复杂度不同;而编码算法则不一样,其过程是不可逆的。
密码明文编码之后,只有用户知道密码,甚至后台管理员都无法直接看到用户的密码明文。当用户忘记密码后,只能重置密码(通过手机验证码或者邮箱的形式)。所以,即使数据库泄露,黑客也很难破解密码。
推荐使用BCryptPasswordEncoder来进行密码明文的编码,本文配套的微服务脚手架中通过配置类配置了一个全局的加密器IOC容器实例,参考代码如下:
package com.crazymaker.springcloud.standard.config;
//省略import
/**
*密码加密器配置类
*/
@Configuration
public class DefaultPasswordConfig
{
/**
*装配一个全局的Bean,用于密码加密和匹配
*
*@return BCryptPasswordEncoder加密器实例
*/
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
此类处于脚手架的base-runtime模块中,默认已经完成了Bean的装配,其他的模块只要直接通过@Resource注解装配即可。
作为基于数据源的认证流程演示程序,这里简单改造6.4.2节的实例,使用基于数据源的请求认证方式完成认证处理,并且依据6.4.2节中认证流程的5个步骤进行说明。
演示程序的第一步:定制一个凭证/令牌类。本演示程序直接使用Spring Security提供的
UsernamePasswordAuthenticationToken认证类存放用户名+密码信息,故这里不再定制自己的凭证/令牌类。
演示程序的第二步:定制一个认证提供者类和凭证/令牌类进行配套。
本演示程序直接使用Spring Security提供的提供者实现类DaoAuthenticationProvider,并在项目的Spring Security的启动配置类(本演示程序中为DemoWebSecurityConfig类)中创建该提供者的Bean实例。需要注意的是,该提供者有两个依赖:一个是UserDetailsService类型的用户信息服务实例;另一个是PasswordEncoder类型的加密器实例。
在项目的启动配置类中装配DaoAuthenticationProvider提供者容器实例的参考代码如下:
package com.crazymaker.springcloud.demo.config;
...
@EnableWebSecurity
public class DemoWebSecurityConfig extends WebSecurityConfigurerAdapter
{
...
//注入全局BCryptPasswordEncoder加密器容器实例
@Resource
private PasswordEncoder passwordEncoder;
//注入数据源服务容器实例
@Resource
private DemoAuthUserService demoUserAuthService;
@Bean("daoAuthenticationProvider")
protected AuthenticationProvider daoAuthenticationProvider() throws Exception
{
//创建一个数据源提供者
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
//设置加密器
daoProvider.setPasswordEncoder(passwordEncoder);
//设置用户数据源服务
daoProvider.setUserDetailsService(demoUserAuthService);
return daoProvider;
}
}
代码中所依赖的PasswordEncoder类的加密器IOC实例会注入base-runtime模块所装配的全局BCryptPasswordEncoder类的passwordEncoder Bean。代码中所依赖的数据源服务IOC实例的类是一个自定义的数据源服务类,名为DemoAuthUserService,核心代码如下:
package com.crazymaker.springcloud.demo.security;
//省略import
@Slf4j
@Service
public class DemoAuthUserService implements UserDetailsService
{
//模拟的数据源,实际从DB中获取
private Map<String, String> map = new LinkedHashMap<>();
//初始化模拟的数据源,放入两个用户
{
map.put("zhangsan", "123456");
map.put("lisi", "123456");
}
/**
*装载系统配置的加密器
*/
@Resource
private PasswordEncoder passwordEncoder;
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException
{
//实际场景中需要从数据库加载用户
//这里出于演示的目的,用map模拟真实的数据源
String password = map.get(username);
if (password == null)
{
return null;
}
if (null == passwordEncoder)
{
passwordEncoder = CustomAppContext.getBean
(PasswordEncoder.class);
}
/**
*返回一个用户详细实例,包含用户名、加密后的密码、用户权限清单、用户角色
*/
UserDetails userDetails = User.builder()
.username(username)
.password(passwordEncoder.encode(password))
.authorities(SessionConstants.USER_INFO)
.roles("USER")
.build();
return userDetails;
}
}
Spring Security的DaoAuthenticationProvider在验证令牌时,会将令牌中的密码明文和用户详细实例UserDetails中的密码密文通过其内部的PasswordEncoder加密器实例进行匹配。所以,UserDetails中的密文在加密时用的加密器和DaoAuthenticationProvider中的认证加密器是同一种类型,需要使用同样的编码/加密算法,以保证能匹配成功。本演示程序中,由于二者使用的都是全局加密器IOC容器实例,因此加密器的类型和算法自然是一致的。
演示程序的第三步:定制一个过滤器类,从请求中获取用户信息组装成定制凭证/令牌,交给认证管理者。这一步使用6.4.2节的DemoAuthFilter过滤器,仅进行简单的修改:从请求中获取token头部字段,解析之后组装成UserDetails,然后构造一个“用户名+密码”类型的
UsernamePasswordAuthenticationToken令牌实例,提交给AuthenticationManager进行验证。
package com.crazymaker.springcloud.demo.security;
//省略import
public class DemoAuthFilter extends OncePerRequestFilter
{
...
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException
{
...
try
{
Authentication returnToken=null;
boolean succeed=false;
String token = request.getHeader(SessionConstants
.AUTHORIZATION_HEAD);
String[] parts = token.split("," );
//方式二:数据源认证演示
UserDetails userDetails = User.builder()
.username(parts[0])
.password(parts[1])
.authorities(SessionConstants.USER_INFO)
.build();
//创建一个用户名+密码的凭证,一般情况下,令牌中的密码需要明文
Authentication userPassToken = new UsernamePasswordAuthenticationToken(userDetails,
userDetails.getPassword(),
userDetails.getAuthorities());
//进入认证流程
returnToken =this.getAuthenticationManager()
.authenticate(userPassToken);
succeed=userPassToken.isAuthenticated();
if (succeed)
{
//认证成功,设置上下文令牌
SecurityContextHolder.getContext()
.setAuthentication(returnToken);
//执行后续的操作
filterChain.doFilter(request, response);
return;
}
} catch (Exception e)
{
logger.error("认证有误", e);
failed = new AuthenticationServiceException("请求头认证消息格式错误",e );
}
...
}
...
}
以上过滤器实现代码除了认证的令牌不同之外,其他的代码和6.4.2节基本是一致的。
演示程序的第四步:定制一个HTTP的安全认证配置类(AbstractHttpConfigurer子类),将上一步定制的过滤器加入请求的过滤处理责任链。
演示程序的第五步:定义一个Spring Security安全配置类(
WebSecurityConfigurerAdapter子类),对Web容器的HTTP的安全认证机制进行配置。
第四步、第五步的实现代码和6.4.2节中第四步、第五步的实现代码是完全一致的,这里不再赘述。
完成以上五步后,一个基于数据源的认证流程就完成了。重启项目后,可以参考6.4.2节的自验证方法进行Spring Security的认证拦截验证。
本文给大家讲解的内容是 微服务网关与用户身份识别,Spring Security原理和实战
- 下篇文章给大家讲解的是微服务网关与用户身份识别,JWT+Spring Security进行网关安全认证;
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!