Spring Security 簡介
背景分析
企業中資料是最重要的資源,對于這些資料而言,有些可以直接匿名訪問,有些只能登錄以后才能訪問,還有一些你登錄成功以后,權限不夠也不能訪問.總之這些規則都是保護系統資源不被破壞的一種手段.幾乎每個系統中都需要這樣的措施對資料(資源)進行保護.我們通常會通過軟體技術對這樣業務進行具體的設計和實作.早期沒有統一的標準,每個系統都有自己獨立的設計實作,但是對于這個業務又是一個共性,后續市場上就基于共享做了具體的落地實作,例如Spring Security,Apache shiro誕生了.
認證授權分析
用戶在進行資源訪問時,要求系統要對用戶進行權限控制,其具體流程如圖所示:

Spring Security 概述
Spring Security 是一個企業級安全框架,由spring官方推出,它對軟體系統中的認證,授權,加密等功能進行封裝,并在springboot技術推出以后,配置方面做了很大的簡化.市場上現在的分布式架構下的安全控制正在逐步的轉向Spring Security.
Spring Security 基本架構
Spring Security 在企業中實作認證和授權業務時,底層構建了大量的過濾器.

其中:
綠色部分為認證過濾器,需要我們自己配置,也可以配置過個認證過濾器.也可以使用Spring Security提供的默認認證過濾器.黃色部分為授權過濾器.Spring Security就是通過這些過濾器然后呼叫相關物件一起完成認證和授權操作.
Spring Security 快速入門
創建工程

添加專案依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.3.2.RELEASE</version>
</parent>
<groupId>com.cy</groupId>
<artifactId>02-jt-spring-security</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
創建組態檔
在resources目錄下創建application.yml檔案,并指定服務埠
server:
port: 8080
創建專案啟動類
package com.cy.jt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(
SpringSecurityApplication.class,
args);
}
}
運行啟動類訪問測驗
第一步:檢查控制輸出,是否自動生成了一個密碼,例如:
Using generated security password: 360123aa-df93-4cd9-bab4-5212af421d2c
第二步:打開瀏覽器輸入http://localhost:8080,然后呈現登錄頁面,例如:

在登錄視窗中輸入用戶名user(系統默認),密碼(服務啟動時,控制臺默認輸出的
密碼),然后點擊Sign in進行登錄,登錄成功默認會出現,如下界面:

定義登錄成功頁面
在專案的resources目錄下創建static目錄,并在此目錄創建一個index.html檔案,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Login Ok</h1>
</body>
</html>
啟動服務,再次進行登錄訪問測驗,登錄成功以后系統默認會跳轉到index.html頁面,例如

配置登錄密碼
第一步:撰寫一個方法(可以在啟動類中呼叫執行),對一個名文進行加密,例如:
static void encodePwd(){
BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
String password="123456";//明文
String newPwd=encoder.encode("123456");
System.out.println(newPwd);//$2a$10$fahHJIe3SJm3KcyiPPQ2d.a2qR029gB3qKHrKanQ87u.KbtZ6Phr.
}
第二步:將用戶和密碼在在springboot工程的application.yml檔案中進行配置,例如:
spring:
security:
user:
name: jack
#password: 123456 #這種寫法,密碼太簡單了
password: '{bcrypt}$2a$10$fahHJIe3SJm3KcyiPPQ2d.a2qR029gB3qKHrKanQ87u.KbtZ6Phr.'
其中,{bcrypt}指定了密碼加密時使用的演算法
第三步:啟動服務,重新進行登錄測驗.
SpringSecurity 認證邏輯實作
自定義登陸邏輯
SpringSecurity支持通過組態檔的方式定義用戶資訊(賬號密碼和角色等),但這種方式有明顯的缺點,那就是系統上線后,用戶資訊的變更比較麻煩,因此SpringSecurity還支持通過實作UserDetailsService介面的方式來提供用戶認證授權資訊,其應用程序如下:
第一步:定義security配置類,例如:
/**
* 由@Configuration注解描述的類為spring中的配置類,配置類會在spring
* 工程啟動時優先加載,在配置類中通常會對第三方資源進行初始配置.
*/
@Configuration
public class SecurityConfig {
/**
* 定義SpringSecurity密碼加密物件
* @Bean 注解通常會在@Configuration注解描述的類中描述方法,
* 用于告訴spring框架這個方法的回傳值會交給spring管理,并spring
* 管理的這個物件起個默認的名字,這個名字與方法名相同,當然也可以通過
* @Bean注解起名字
*/
@Bean //物件名默認為方法名
//@Bean("bcryptPasswordEncoder")//bean物件名字為bcryptPasswordEncoder
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
第二步:定義UserDetailService介面實作類,自定義登陸邏輯,代碼如下:
UserDetailService為SpringSecurity官方提供的登錄邏輯處理物件,我們自己可以實作此介面,然后在對應的方法中進行登錄邏輯的撰寫即可.
package com.cy.jt.security.service;
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
/**
* 當我們執行登錄操作時,底層會通過過濾器等物件,呼叫這個方法.
* @param username 這個引數為頁面輸出的用戶名
* @return 一般是從資料庫基于用戶名查詢到的用戶資訊
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
//1.基于用戶名從資料庫查詢用戶資訊
//User user=userMapper.selectUserByUsername(username);
if(!"jack".equals(username))//假設這是從資料庫查詢的資訊
throw new UsernameNotFoundException("user not exists");
//2.將用戶資訊封裝到UserDetails物件中并回傳
//假設這個密碼是從資料庫查詢出來的
String encodedPwd=passwordEncoder.encode("123456");
//假設這個權限資訊也是從資料庫查詢到的
//假如分配權限的方式是角色,撰寫字串時用"ROLE_"做前綴
List<GrantedAuthority> grantedAuthorities =
AuthorityUtils.commaSeparatedStringToAuthorityList(
"ROLE_admin,ROLE_normal,sys:res:retrieve,sys:res:create");
//這個user是SpringSecurity提供的UserDetails介面的實作,用于封裝用戶資訊
//后續我們也可以基于需要自己構建UserDetails介面的實作
User user=new User(username,encodedPwd,grantedAuthorities);
return user;
}
}
說明,這里的User物件會交給SpringSecurity框架,框架提取出密碼資訊,然后與用戶輸入的密碼進行匹配校驗.
第三步:啟動服務進行登陸,訪問測驗,


自定義登陸頁面
第一步:定義登陸頁面(直接在static目錄下創建即可),關鍵代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Please sign in</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">Please sign in</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
</p>
<input name="_csrf" type="hidden" value="cc1471a5-3246-43ff-bef7-31d714273899" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</body>
</html>
注意:請求的url暫時為”/login”,請求方式必須為post方式,請求的引數暫時必須為username,password,這些規則默認在UsernamePasswordAuthenticationFilter中進行了定義,
第二步:修改安全配置類,讓其實作介面,并重寫相關config方法,進行登陸設計,代碼如下:
@Configuration
public class SecutiryConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);
//關閉跨域攻擊,不關閉容易出錯
http.csrf().disable();
//自定義登陸表單
http.formLogin()
//設定登陸頁面
.loginPage("/login.html")
//設定登陸請求處理地址(對應form表單中的action),登陸時會訪問UserDetailService物件
.loginProcessingUrl("/login")
//設定請求用戶名引數為username(默認就是username,可以自己修改,需要與表單同步)
.usernameParameter("username")
//請求請求密碼引數為password(默認就是password,可以自己修改,需要與表單同步)
.passwordParameter("password")
//設定登陸成功跳轉頁面(默認為/index.html)
.defaultSuccessUrl("/index.html")
//登陸失敗訪問的頁面(默認為/login.html?error)
.failureUrl("/login.html?error");
//認證設計
http.authorizeRequests()
//設定要放行的咨詢
.antMatchers("/login.html").permitAll()
//設定需要認證的請求(除了上面的要放行,其它都要進行認證)
.anyRequest().authenticated();
}
}
登陸成功和失敗處理器
現在的很多系統都采用的是前后端分離設計,我們登陸成功以后可能會跳轉到前端系統的某個地址,或者回傳一個json資料,我們可以自己定義登錄成功的處理操作,例如:
定義登陸成功處理器:
方案1:可以直接執行重定向的處理器,例如
package com.cy.jt.auth.config.authentication;
public class RedirectAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
//定義要跳轉的url
private String redirectUrl;
public RedirectAuthenticationSuccessHandler(String redirectUrl){
this.redirectUrl=redirectUrl;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,
Authentication authentication)
throws IOException, ServletException {
httpServletResponse.sendRedirect(redirectUrl);
}
}
方案2:可以直接回傳JSON資料的處理器,例如:
package com.cy.jt.security.config.handler;
/**處理登錄失敗
* 0)Default-默認
* 1)Authentication-認證
* 2)Failure-失敗
* 3)Handler-處理器
* */
public class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
//1.設定回應資料的編碼
httpServletResponse.setCharacterEncoding("utf-8");
//2.告訴客戶端回應資料的型別,以及客戶端以怎樣的編碼進行顯示
httpServletResponse.setContentType("application/json;charset=utf-8");
//3.獲取一個輸出流物件
PrintWriter out=httpServletResponse.getWriter();
//4.向客戶端輸出一個json格式字串
//4.1構建一個map物件
Map<String,Object> map=new HashMap<>();
map.put("state","500");
map.put("msg","username or password error");
//4.2基于jackson中的ObjectMapper物件將一個物件轉換為json格式字串
String jsonStr= new ObjectMapper().writeValueAsString(map);
out.println(jsonStr);
out.flush();
}
}
定義登陸失敗處理器:
方案1:登陸失敗重定向到頁面,例如
package com.cy.jt.auth.config.authentication;
public class RedirectAuthenticationFailureSuccessHandler implements AuthenticationFailureHandler {
private String redirectUrl;
public RedirectAuthenticationFailureSuccessHandler(String redirectUrl){
this.redirectUrl=redirectUrl;
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect(redirectUrl);
}
}
方案2:定義登陸失敗處理器,例如:
package com.cy.jt.security.config.handler;
/**處理登錄失敗
* 0)Default-默認
* 1)Authentication-認證
* 2)Failure-失敗
* 3)Handler-處理器
* */
public class DefaultAuthenticationFailureHandler
implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
//1.設定回應資料的編碼
httpServletResponse.setCharacterEncoding("utf-8");
//2.告訴客戶端回應資料的型別,以及客戶端以怎樣的編碼進行顯示
httpServletResponse.setContentType("application/json;charset=utf-8");
//3.獲取一個輸出流物件
PrintWriter out=httpServletResponse.getWriter();
//4.向客戶端輸出一個json格式字串
//4.1構建一個map物件
Map<String,Object> map=new HashMap<>();
map.put("state","500");
map.put("msg","username or password error");
//4.2基于jackson中的ObjectMapper物件將一個物件轉換為json格式字串
String jsonStr= new ObjectMapper().writeValueAsString(map);
out.println(jsonStr);
out.flush();
}
}
修改配置類,設定登陸成功與失敗處理器,
@Configuration
public class SecutiryConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);
//關閉跨域攻擊,不關閉容易出錯
http.csrf().disable();
//自定義登陸表單
http.formLogin()
//設定登陸頁面
.loginPage("/login.html")
//設定登陸請求處理地址(對應form表單中的action),登陸時會訪問UserDetailService物件
.loginProcessingUrl("/login")
//設定請求用戶名引數為username(默認就是username,可以自己修改,需要與表單同步)
.usernameParameter("username")
//請求請求密碼引數為password(默認就是password,可以自己修改,需要與表單同步)
.passwordParameter("password")
//設定登陸成功跳轉頁面(默認為/index.html)
.successHandler(new RedirectAuthenticationSuccessHandler("你的url"))
//登陸失敗訪問的頁面(默認為/login.html?error)
.failureHandler(new RedirectAuthenticationFailureHandler("你的url"))
//認證設計
http.authorizeRequests()
//設定要放行的咨詢
.antMatchers("/login.html").permitAll()
//設定需要認證的請求(除了上面的要放行,其它都要進行認證)
.anyRequest().authenticated();
}
}
第四步:啟動服務進行訪問測驗(分別用正確和錯誤的賬號進行測驗),
放行靜態資源
在SecurityManager配置類中的configure(HttpSecurity http)方法中我們可以通過對anMatchers方法定義要放行靜態資源,例如:
.authorizeRequests() //設定請求的授權
.antMatchers( //配置下列路徑的授權
"/index.html",
"/js/*",
"/css/*",
"/img/**",
"/bower_components/**",
"/login.html"
).permitAll() //設定上述所有路徑不需要登錄就能訪問(放行)
其中:
- “*”用于匹配0個或多個字符
- “**”用于匹配0個或多個目錄及字符
登出設計及實作
在SecurityManager配置類中的configure(HttpSecurity http)方法中,添加登出配置,例如
http.logout() //開始設定登出資訊
.logoutUrl("/logout") //登出路徑
.logoutSuccessUrl("/login.html?logout");//設定登出后顯示的頁面
SpringSecurity授權邏輯實作
修改授權配置類
在權限配置類上添加啟用全域方法訪問控制注解,例如:
package com.cy.auth.config;
//這個配置類是配置Spring-Security的,
//prePostEnabled= true表示啟動權限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SpringSecurityConfigurer extends WebSecurityConfigurerAdapter {
……
}
定義資源Controller
定義一個ResourceController類,作為資源訪問物件,例如
package com.cy.jt.auth.controller;
@RestController
public class ResourceController {
@PreAuthorize("hasAuthority('sys:res:create')")
@RequestMapping("/doCreate")
public String doCreate(){
return "add resource";
}
@PreAuthorize("hasAuthority('sys:res:update')")
@RequestMapping("doUpdate")
public String doUpdate(){
return "update resource";
}
@PreAuthorize("hasAuthority('sys:res:delete')")
@RequestMapping("/doDelete")
public String doDelete(){
return "delete resource";
}
@PreAuthorize("hasAuthority('sys:res:retrieve')")
@RequestMapping("/doRetrieve")
public String doRetrieve(){
return "retrieve resource";
}
}
其中,@PreAuthorize注解描述方法時,用于告訴系統訪問此方法時需要進行權限檢測,需要具備指定權限才可以訪問,例如:
- @PreAuthorize(“hasAuthority('sys:res:delete”) 需要具備sys:res:delete權限
- @PreAuthorize(“hasRole(‘admin’)”) 需要具備admin角色
啟動服務訪問測驗
使用不同用戶進行登陸,然后執行資源訪問,假如沒有權限,則會看到回應狀態嗎403,如圖所示:

Spring認證和授權例外處理
例外型別
對于SpringSecurity框架而言,在實作認證和授權業務時,可能出現如下兩大型別例外:
1)AuthenticationException (用戶還沒有認證就去訪問某個需要認證才可訪問的方法時,可能出現的例外,這個例外通常對應的狀態碼401)
2)AccessDeniedException (用戶認證以后,在訪問一些沒有權限的資源時,可能會出現的例外,這個例外通常對應的狀態嗎為403)
例外處理規范
SpringSecurity框架給了默認的例外處理方式,當默認的例外處理方式不滿足我們實際業務需求時,此時我們就要自己定義例外處理邏輯,撰寫邏輯時需要遵循如下規范:
1)AuthenticationEntryPoint:統一處理 AuthenticationException 例外
2)AccessDeniedHandler:統一處理 AccessDeniedException 例外.
自定義例外處理物件
處理沒有認證的訪問例外
package com.cy.jt.config;
public class DefaultAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
//設定回應資料的編碼
response.setCharacterEncoding("utf-8");
//告訴瀏覽器要回應的內容型別,以及編碼
response.setContentType("application/json;charset=utf-8");
Map<String,Object> map=new HashMap<>();
map.put("state",401);
map.put("message","請先登錄");
PrintWriter out=response.getWriter();
out.println(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
}
處理沒有權限時拋出的例外
package com.cy.jt.config;
public class DefaultAccessDeniedExceptionHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException e) throws IOException, ServletException {
//設定回應資料的編碼
response.setCharacterEncoding("utf-8");
//告訴瀏覽器要回應的內容型別,以及編碼
response.setContentType("application/json;charset=utf-8");
Map<String,Object> map=new HashMap<>();
map.put("state",403);
map.put("message","沒有此資源的訪問權限");
PrintWriter out=response.getWriter();
out.println(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
}
配置例外處理物件
在配置類SecurityConfig中添加自定義例外處理物件,代碼如下
http.exceptionHandling()
.authenticationEntryPoint(new DefaultAuthenticationEntryPoint())
.accessDeniedHandler(new DefaultAccessDeniedExceptionHandler());
配置完成后,重啟服務進行訪問測驗分析.
系統會話狀態分析與實踐
何為會話狀態
客戶端與服務端通訊程序中產生的狀態資訊(類似會議記錄),稱之為會話狀態.
會話狀態如何存盤
客戶端瀏覽器與服務端通訊時使用的是http協議,這個協議本身是無狀態協議,也就是說通過此協議,無法存盤會話狀態,此時在服務端與客戶端就采用了一種Cookie與Session方式記錄會話狀態.
有狀態的會話技術分析
- Cookie 技術
Cookie是由服務端創建但在客戶端存盤會話狀態的一個物件,此物件分為兩種型別,一種為會話Cookie,一種為持久Cookie,瀏覽器在訪問具體的某個域名時會攜帶這個域的有效Cookie到服務端.
- 會話Cookie: 瀏覽器關閉Cookie生命周期結束(一般默認都是會話Cookie)
- 持久Cookie: 持久Cookie是在Cookie物件創建時指定了生命周期,例如一周時間,即便瀏覽器關閉,持久Cookie依舊有效.
- Session技術
Session技術由服務端創建,并在服務端存盤會話狀態的一個物件,當Session物件創建時,還會創建一個會話Cookie物件,并且通過這個會話Cookie將SessionId寫到客戶端,客戶端下次訪問服務端會攜帶這個會話Cookie,并且通過JsessionId找到Session物件,進而獲取Session物件中存盤的資料.Cookie默認的生命周期為30分鐘.
在SpringSecurity中獲取用戶的認證資訊,就可以通過如下方式進行實作:
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
無狀態的會話技術分析
有狀態的會話實作,在分布式架構中可能會存在很多問題,例如瀏覽器默認不支持攜帶其它域的Cookie資訊進行資源訪問,同時服務端的Session默認不能共享,當然我們有一種方式可以將session持久化到到一些資料庫,例如Redis,下次請求到其它服務器(例如tomcat)時,可以直接從redis中獲取登錄資訊,但是假如并發比較大,資料庫的訪問壓力就會劇增,壓力太大有可能會導致系統宕機.所以現在還有一種方案就是將用戶的登錄狀態資訊都存盤在客戶端,服務端不記錄任何狀態,服務端只負責對客戶端傳遞過來的狀態資訊進行決議,基于此方式進行用戶登錄狀態的判斷,這樣的會話程序稱之為無狀態會話.
總結(Summary)
重難點分析
- SpringSecurity 產生背景?
- SpringSecurity 快速入門?(依賴,配置,登錄認證,密碼的加密-啟動生成,組態檔)
- SpringSecurity 認證邏輯分析及實踐?(認證方式-用戶名和密碼,登錄頁
面,SecurityConfig.UserServiceDetail,成功,失敗,放行) - SpringSecurity 授權邏輯分析及實作?(為什么,授權步驟,用到的注解)
FAQ 分析
- 如何理解認證?(判定用戶身份的合法性)
- 如何校驗用戶身份的合法性?(用戶密碼,指紋,刷臉,刷身份證,…)
- 如何進行身份認證?(自己寫認證邏輯,借助框架去寫認證邏輯-尊重框架規則)
- 市場上的認證和授權框架有哪些?(SpringSecurity,Shiro)
- 為什么會選擇SpringSecurity?(功能強大,SpringBoot誕生后在配置方面做了大量的簡化)
- SpringSecurity中的加密方式你用的什么?(Bcrypt,底層基于隨機鹽方式對密碼進行hash不可逆加密,更加安全,缺陷是慢)
- SpringSecurity中你用過哪些API?(BcryptPasswordEncoder,UserDetailService,UserDetail,User,
AuthenticationSuccessHandler,AuthenticationFailureHandler,…) - 為什么要進行權限控制?(防止非法用戶破壞資料)
- SpringSecurity進行權限控制的步驟(@EnableGlobalMethodSecurity,@PreAuthorize)
- SpringSecurity在進行認證和授權時可能出現的例外?
- SpringSecurity在未認證和未授權的前提下訪問授權資源時,出現的例外如何處理?
- 作業:用戶登錄成功以后,用戶資訊默認存在哪里了? (Session)
- 作業:用戶登錄成功以后,如何獲取我們登錄的用戶資訊?(這個用戶的用戶名,這個用戶的權限)
Bug 分析
- 依賴下載不完整
- 回應json資料時出現檔案下載
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/289440.html
標籤:java
