文章目錄
- 一、什么是 Spring Security?
- 官方介紹
- 通俗來講
- 二、初始搭建
- 創建
- 啟動
- 三、專案原理
- 原理
- 思考
- 四、登錄認證
- 登錄過濾器
- 配置過濾器鏈
- 類補充
- 五、登錄效果
- 效果演示
- 請求后臺介面
- 末、系列文章
一、什么是 Spring Security?
官方介紹
- Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security是一個功能強大且高度可定制的身份認證和訪問控制框架,它是保護基于spring應用程式的事實標準,
- Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements.
Spring Security是一個重點為Java應用程式提供認證和授權的框架,與所有Spring專案一樣,Spring Security的真正強大之處在于它可以很容易地擴展以滿足定制需求,
通俗來講
- 首先我們前端應用訪問后臺資源,比如后臺介面,是需要
帶上訪問憑證(令牌)的,我們肯定不能夠直接將介面資源暴露給前端應用,這有很大安全隱患, - 這個框架就是方便了獲取憑證流程,其重點在于
認證和授權,認證就是對你的身份進行認證,比如校驗用戶名密碼是否正確、手機號是否正確、是否在我們庫中存在該手機號用戶,認證的目的就是為了授權,授權的結果就是給到前端一個訪問憑證,比如給到前端一個JWT令牌, - 前端有了這個令牌,每次請求帶上令牌就可以訪問后臺資源了,當然每次訪問資源之前,后臺都會對這個令牌進行一個
校驗,判斷這個令牌是否有效是否已過期等等, - 可以暫時把它單純的理解為
登錄認證用的,
二、初始搭建
創建
-
創建一個Maven空專案,引入依賴,創建主類

-
引入兩個依賴
spring-boot-starter-web、spring-boot-starter-security
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>
</dependencies>
- 創建啟動類,同時定義一個
/hello介面
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/hello")
public String hello() {
return "Hello Spring Security!";
}
}
啟動
- 啟動日志
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.9.RELEASE)
2021-04-24 10:38:10.193 INFO 7684 --- [ main] com.meicloud.security.DemoApplication : Starting DemoApplication on DESKTOP-T2KEH3M with PID 7684 (C:\Users\85176\Desktop\spring-security-demo\target\classes started by 85176 in C:\Users\85176\Desktop\spring-security-demo)
2021-04-24 10:38:10.195 INFO 7684 --- [ main] com.meicloud.security.DemoApplication : No active profile set, falling back to default profiles: default
2021-04-24 10:38:10.237 INFO 7684 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6d4d66d2: startup date [Sat Apr 24 10:38:10 CST 2021]; root of context hierarchy
2021-04-24 10:38:11.337 INFO 7684 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2021-04-24 10:38:11.347 INFO 7684 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-04-24 10:38:11.348 INFO 7684 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2021-04-24 10:38:11.461 INFO 7684 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-04-24 10:38:11.461 INFO 7684 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1227 ms
2021-04-24 10:38:11.679 INFO 7684 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2021-04-24 10:38:11.679 INFO 7684 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2021-04-24 10:38:11.679 INFO 7684 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2021-04-24 10:38:11.679 INFO 7684 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2021-04-24 10:38:11.680 INFO 7684 --- [ost-startStop-1] .s.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
2021-04-24 10:38:11.680 INFO 7684 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2021-04-24 10:38:11.963 INFO 7684 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6d4d66d2: startup date [Sat Apr 24 10:38:10 CST 2021]; root of context hierarchy
2021-04-24 10:38:12.043 INFO 7684 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello],methods=[GET]}" onto public java.lang.String com.meicloud.security.DemoApplication.hello()
2021-04-24 10:38:12.047 INFO 7684 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2021-04-24 10:38:12.048 INFO 7684 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2021-04-24 10:38:12.101 INFO 7684 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2021-04-24 10:38:12.101 INFO 7684 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2021-04-24 10:38:12.158 INFO 7684 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2021-04-24 10:38:12.371 INFO 7684 --- [ main] b.a.s.AuthenticationManagerConfiguration :
Using default security password: 03deaaa0-d17f-445a-abf0-f21b2a6cf554
2021-04-24 10:38:12.424 INFO 7684 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/css/**'], Ant [pattern='/js/**'], Ant [pattern='/images/**'], Ant [pattern='/webjars/**'], Ant [pattern='/**/favicon.ico'], Ant [pattern='/error']]], []
2021-04-24 10:38:12.522 INFO 7684 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3e15bb06, org.springframework.security.web.context.SecurityContextPersistenceFilter@2cfa2c4f, org.springframework.security.web.header.HeaderWriterFilter@66c38e51, org.springframework.security.web.authentication.logout.LogoutFilter@5fe7f967, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@3f049056, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@48eb9836, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@79d06bbd, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6778aea6, org.springframework.security.web.session.SessionManagementFilter@12968227, org.springframework.security.web.access.ExceptionTranslationFilter@58cf8f94, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@27b45ea]
2021-04-24 10:38:12.664 INFO 7684 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2021-04-24 10:38:12.716 INFO 7684 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2021-04-24 10:38:12.720 INFO 7684 --- [ main] com.meicloud.security.DemoApplication : Started DemoApplication in 2.804 seconds (JVM running for 5.014)
- 訪問介面
http://localhost:8080/hello,能彈出這個登錄框就說明專案已經被Spring Security應用了,其實這個登錄認證使用的是默認的登錄過濾器,末尾放出相關原始碼文章,如果有興趣可以了解了解是怎么配置的默認過濾器,

- 默認用戶名是
user,密碼在控制臺已列印出來了,輸入即可登錄,登錄后即可訪問后臺資源,

三、專案原理
原理
在實戰之前你需要了解一些關于這個框架的原理,其實這個框架的核心是創建一個
FilterChainProxy型別的過濾器,這個過濾器里面維護了一組過濾器鏈,而我們要做的是創建一條我們自己的過濾器鏈,當然創建流程框架幫我們搞定了,我們要做的是把自己的過濾器鏈配置進框架,由框架幫我們創建出過濾器鏈,因此:
- 目的很明確:創建一條過濾器鏈,
- 操作很簡單:配置我們的過濾器鏈到框架,
思考
只是要寫一個登錄介面,也就是一個過濾器就行了,為什么要配置一條過濾器鏈?
- 其實你確實只要寫一個登錄過濾器就行,但還是要加入到過濾器鏈中,你也需要(可選)很多其他的過濾器,比如
請求頭過濾器、跨域資源共享過濾器、登出過濾器、Session過濾器等等,這些過濾器框架都已經提供了,可以直接配置, - 你要知道使用這個框架的目的,
一個是方便搭建我們的過濾器,一個是它提供了很多默認的強大的過濾器,不用我們重新寫,這是我們用這個框架的原因,大概就是圖個方便,
四、登錄認證
Github專案地址:spring-security-demo,其中類里完善了大量詳細的描述,如果有用請默默點個贊,如果不理解可以評論一起探討,
首先明確要做的是
創建一個登錄過濾器,配置一條過濾器鏈,大致看看要創建的類,接下來一個一個了解:
登錄過濾器
完整的登錄過濾器應該包含很多組成部分,包括過濾器本身(
UnionidAuthenticationFilter),認證用的Provider(UnionidAuthenticationProvider),登錄成功處理器(UnionidLoginSuccessHandler),登錄失敗處理器(HttpStatusLoginFailureHandler),還有最后一個過濾器配置器(UnionidLoginConfigurer),一個一個來說:
- 登錄過濾器:一般會繼承抽象類
AbstractAuthenticationProcessingFilter,實作它的attemptAuthentication方法,登錄的URL是/user/members:login,
/**
* 登錄認證過濾器
*/
public class UserAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public UserAuthenticationFilter() {
super(new AntPathRequestMatcher("/user/login", "POST"));
}
@Override
public void afterPropertiesSet() {
Assert.notNull(this.getAuthenticationManager(), "AuthenticationManager must be specified");
Assert.notNull(this.getSuccessHandler(), "AuthenticationSuccessHandler must be specified");
Assert.notNull(this.getFailureHandler(), "AuthenticationFailureHandler must be specified");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
// TODO 這里的邏輯主要有兩個作用,一個是進行初步的校驗,一個是組裝待認證的Token,舉幾個例子:
// 1.微信授權登錄:客戶端會傳過來一些加密串,這里邏輯主要解密這些加密串的資料獲取unionId、openId、手機號以及用戶昵稱頭像等基本資訊,
// 然后組裝Token傳給Provider進行下一步認證,如果這里報錯直接就回傳例外,不會進行下一步認證,
// 2.手機短信驗證碼登錄:這里主要驗證短信驗證碼的正確性,然后組裝Token傳給Provider進行下一步認證,如果短信驗證碼錯誤直接拋例外
// 3.賬號密碼圖形驗證碼登錄:這里主要驗證圖形驗證碼的正確性,然后組裝Token傳給Provider進行下一步認證,如果圖形驗證碼錯誤直接拋例外
// ...
// =================================================== 示例 ===============================================
String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
String mobile = null, password = null, verifyCode = null;
if(StringUtils.hasText(body)) {
UserLoginRequest loginRequest = JSON.parseObject(body, UserLoginRequest.class);
mobile = loginRequest.getMobile();
password = loginRequest.getPassword();
verifyCode = loginRequest.getVerifyCode();
}
// TODO 這里驗證圖形驗證碼 verifyCode 是否正確
UserAuthenticationToken token = new UserAuthenticationToken(
null, mobile, password);
// 這里進行下一步認證,會走到我們定義的 UserAuthenticationProvider 中
return this.getAuthenticationManager().authenticate(token);
}
}
- 認證用的Provider:需要實作
AuthenticationProvider介面,實作authenticate()、supports()方法,
/**
* Unionid認證 Provider
*/
public class UserAuthenticationProvider implements AuthenticationProvider {
public UserAuthenticationProvider() {
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// TODO 這里主要進行一個資料庫層面的認證,比如賬號密碼的正確性,比如該賬號是否被拉黑有什么權限等,都認證成功之后會組裝一個認證通過的 Token
// 這里認證成功回傳之后會跑到成功處理器:UserLoginSuccessHandler
// 只要整個認證(包括前面的校驗)中有一個地方拋出例外都會呼叫失敗處理器:HttpStatusLoginFailureHandler
// =================================================== 示例 ===============================================
UserAuthenticationToken token = (UserAuthenticationToken) authentication;
// 校驗賬號密碼是否正確,同時回傳用戶資訊
UserInfoDTO userInfo = this.checkAndGetUserInfo(token.getMobile(), token.getPassword());
// 組裝并回傳認證成功的 Token
JwtUserLoginDTO jwtUserLoginDTO = new JwtUserLoginDTO(userInfo.getUserId(), userInfo.getNickname(), userInfo.getMobile());
return new JwtAuthenticationToken(jwtUserLoginDTO, null, null);
}
private UserInfoDTO checkAndGetUserInfo(String mobile, String password) {
// 根據手機號查詢用戶資訊,這里假設是根據手機號從資料庫中查出的用戶資訊
UserInfoDTO userInfo = null;
if (mobile.equals("15600000000")) {
userInfo = new UserInfoDTO(100000000L, "張三", "15600000000", "888888");
}
if (Objects.isNull(userInfo)) {
throw LoginAuthenticationException.USER_NAME_NOT_EXIST;
}
// 校驗密碼是否正確
if (!Objects.equals(userInfo.getPassword(), password)) {
// 密碼不正確直接拋例外
throw LoginAuthenticationException.PASSWORD_NOT_EXIST;
}
return userInfo;
}
/**
* 表示這個 Provider 支持認證的 Token(這里是 UserAuthenticationToken)
*
* @param authentication
* @return
*/
@Override
public boolean supports(Class<?> authentication) {
return authentication.isAssignableFrom(UserAuthenticationToken.class);
}
}
- 登錄成功處理器:需要實作
AuthenticationSuccessHandler介面同時實作onAuthenticationSuccess()方法,
/**
* 登錄成功處理器
*/
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler{
public static final String HEADER_SET_ACCESS_TOKEN = "Set-Access-Token";
private SecurityConfig securityConfig;
public UserLoginSuccessHandler(SecurityConfig securityConfig) {
this.securityConfig = securityConfig;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// TODO 走到這里說明認證成功,可以組裝一些回應頭的資訊給到客戶端,比如生成JWT令牌,或者加一些業務上的需求,比如登錄送積分等等
// =================================================== 示例 ===============================================
// 這里的邏輯是生成JWT令牌(很多公司也會用Session),將生成的JWT回傳給前端
Date expiredDate = new Date(System.currentTimeMillis() + securityConfig.getTokenExpireTimeInSecond() * 1000);
Algorithm algorithm = Algorithm.HMAC256(securityConfig.getTokenEncryptSalt());
JwtUserLoginDTO jwtUserLoginDTO = (JwtUserLoginDTO) authentication.getPrincipal();
String token = jwtUserLoginDTO.sign(algorithm, expiredDate);
// 設定請求頭,將JWT令牌以請求頭的方式回傳給前端
response.addHeader(HEADER_SET_ACCESS_TOKEN, token);
}
}
- 登錄失敗處理器:實作
AuthenticationFailureHandler介面同時實作onAuthenticationFailure方法,
/**
* 登錄失敗處理器
*/
public class HttpStatusLoginFailureHandler implements AuthenticationFailureHandler{
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
// TODO 走到這里說明認證流程失敗了,會對例外資訊做一個統一的處理,通過 response 寫回到客戶端
// =================================================== 示例 ===============================================
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.setCharacterEncoding(Charset.defaultCharset().displayName());
if (exception instanceof LoginAuthenticationException) {
LoginAuthenticationException e = (LoginAuthenticationException) exception;
response.getWriter().print(e.toJSONString());
}
response.getWriter().print("登錄例外!");
}
}
- 過濾器配置器:一般繼承
AbstractHttpConfigurer抽象類,實作configure()方法,主要配置成功處理器和失敗處理器,同時將登錄過濾器配置進HttpSecurity,
/**
* 登錄過濾器配置
*/
public class UserLoginConfigurer<T extends UserLoginConfigurer<T, B>, B extends HttpSecurityBuilder<B>> extends AbstractHttpConfigurer<T, B> {
private SecurityConfig securityConfig;
public UserLoginConfigurer(SecurityConfig securityConfig) {
this.securityConfig = securityConfig;
}
@Override
public void configure(B http) throws Exception {
UserAuthenticationFilter authFilter = new UserAuthenticationFilter();
authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
authFilter.setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
// 登錄成功處理器
authFilter.setAuthenticationSuccessHandler(new UserLoginSuccessHandler(securityConfig));
// 登錄失敗處理器
authFilter.setAuthenticationFailureHandler(new HttpStatusLoginFailureHandler());
// 攔截器位置
UserAuthenticationFilter filter = postProcess(authFilter);
http.addFilterAfter(filter, LogoutFilter.class);
}
}
配置過濾器鏈
- 主要配置你需要的過濾器,以及自定義的登錄過濾器,也可以配置哪些URL不應該被過濾器鏈攔截,一般會繼承
WebSecurityConfigurerAdapter抽象類, - 覆寫
configure(HttpSecurity http)方法配置過濾器鏈 - 注意還要覆寫
configure(AuthenticationManagerBuilder auth)方法將前面定義的UnionidAuthenticationProvider配置進AuthenticationManagerBuilder,
/**
* 核心配置器
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SecurityConfig securityConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 配置白名單(比如登錄介面)
.antMatchers(securityConfig.getPermitUrls()).permitAll()
// 其他URL需要認證通過才能訪問后臺資源
.anyRequest().authenticated()
.and()
// 禁用跨站點偽造請求
.csrf().disable()
// 啟用跨域資源共享
.cors()
.and()
// 請求頭
.headers().addHeaderWriter(
new StaticHeadersWriter(Collections.singletonList(
new Header("Access-control-Allow-Origin", "*"))))
.and()
// 自定義的登錄過濾器,不同的登錄方式創建不同的登錄過濾器,一樣的配置方式
.apply(new UserLoginConfigurer<>(securityConfig))
.and()
// 登出過濾器
.logout()
// 登出成功處理器
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
.and()
// 禁用Session會話機制(我們這個demo用的是JWT令牌的方式)
.sessionManagement().disable()
// 禁用SecurityContext,這個配置器實際上認證資訊會保存在Session中,但我們并不用Session機制,所以也禁用
.securityContext().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(userAuthenticationProvider());
}
@Bean
protected AuthenticationProvider userAuthenticationProvider() throws Exception{
return new UserAuthenticationProvider();
}
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
protected CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","HEAD", "DELETE", "PUT","OPTION"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
類補充
由于篇幅太長,其他類請下載原始碼查看,Github專案地址:spring-security-demo
五、登錄效果
本專案用的是JWT,登錄成功后會在回應頭回傳JWT令牌,失敗則顯示錯誤資訊,其中目前后臺模擬了一個用戶名為
15600000000,密碼為888888的用戶,注意后臺并沒有校驗驗證碼,這部分請自行完善,來看看演示效果,
效果演示
- 用戶名輸入錯誤

- 密碼輸入錯誤

- 登錄成功,回傳令牌

請求后臺介面
- 登錄成功后訪問
/hello介面

- 為什么登錄成功了,還是禁止訪問?
其實原因很簡單,這個資源介面沒有帶上登錄回傳的JWT令牌,就算帶上了后臺也沒有識別這個令牌的邏輯,也即后臺還是無法識別普通請求,所以需要加上
識別請求令牌的邏輯,預知后續邏輯,請看下篇講解~
末、系列文章
- 使用 Spring Security 系列文章:
手把手教你如何使用Spring Security(上):登錄授權
手把手教你如何使用Spring Security(下):介面認證
- 如果想深入了解 Spring Security 原始碼,使用的時候為什么需要繼承各種類介面,請參考:
《Spring Security原始碼(一):整體框架設計》
《Spring Security原始碼(二):建造者詳解》
《Spring Security原始碼(三):HttpSecurity詳解》
《Spring Security原始碼(四):配置器詳解》
《Spring Security原始碼(五):FilterChainProxy是如何創建的?》
《Spring Security原始碼(六):FilterChainProxy是如何運行的?》
《Spring Security原始碼(七):設計模式在框架中的應用》
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/280944.html
標籤:其他
上一篇:MyBatis常見面試題

