spring boot整合jwt 實現前后端分離登錄認證及授權


一丶 基本介紹

前后端分離的認證及授權有兩種方式,

第一種是使用jwt 也就是(Json Web Token),客戶端請求服務端,完成賬號密碼的認證以后,由服務端生成一個帶有過期時間的token,返回給客戶端,后續每次請求客戶端都要帶上這個token,服務端從請求中拿到token 進行解析 判斷是否過期,然后構建spring security的安全對象,交由spring security框架進行后續的認證等處理.這種方式相比於傳統的session方式不同,是無狀態的,服務端沒有保存和每個客戶端對應的session對象,而是由客戶端每次請求帶上token,服務端進行解析 來判斷客戶端的身份,這相比傳統方式對服務端的壓力非常小,不需要保存和每個客戶端對應的session對象,而且由於前后端分離,后端更加傾向於提供接口,很多業務邏輯前移,后端只需要認證請求的身份,提供好對應的接口,剩下的權限控制,跳轉頁面等就交由前端實現.

第二種 就是spring cloud的OAuth2認證方式,我這里沒有去研究,所以就不細說了.

我這里也不過多介紹jwt了 百度相關的文章很多,我就直接介紹spring boot怎么整合jwt實現登錄認證及授權

首先貼出maven依賴

 1         <!-- jwt依賴 -->
<dependency> 2 <groupId>io.jsonwebtoken</groupId> 3 <artifactId>jjwt</artifactId> 4 <version>0.9.0</version> 5 </dependency>
   <!--spring security的依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
 

 暫時就引入這兩個依賴吧,一個是jwt,另外一個呢是spring security的依賴

二丶 代碼實現

操作jwt生成token有一個現成的工具類,已經寫好了常用方法,比如根據用戶名生成token,計算token過期時間等方法,我這里先把這個工具類貼上來

 1 import io.jsonwebtoken.Claims;
 2 import io.jsonwebtoken.Jwts;
 3 import io.jsonwebtoken.SignatureAlgorithm;
 4 import org.springframework.beans.factory.annotation.Value;
 5 import org.springframework.security.core.userdetails.UserDetails;
 6 import org.springframework.stereotype.Component;
 7 
 8 import java.io.Serializable;
 9 import java.util.Date;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.function.Function;
13 
14 /**
15  * @Description: JwtTokenUtil,JWT工具類,生成/驗證/是否過期token 。
16  * @Author: Tan
17  * @CreateDate: 2019/12/2
18  **/
19 @Component
20 public class JwtTokenUtil implements Serializable {
21     private static final long serialVersionUID = -2550185165626007488L;
22 
23     //token有效期
24     @Value("${jwt.validity}")
25     private Long tokenValidity;
26 
27 
28     //加密秘鑰
29     @Value("${jwt.secret}")
30     private String secret;
31 
32     //通過token返回用戶名
33     public String getUsernameFromToken(String token) {
34         return getClaimFromToken(token, Claims::getSubject);
35     }
36 
37     //通過token得到token過期時間
38     public Date getExpirationDateFromToken(String token) {
39         return getClaimFromToken(token, Claims::getExpiration);
40     }
41 
42     //從token中獲得用戶信息
43     public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
44         final Claims claims = getAllClaimsFromToken(token);
45         return claimsResolver.apply(claims);
46     }
47 
48     //從token中解密 獲得用戶信息
49     private Claims getAllClaimsFromToken(String token) {
50          return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
51     }
52 
53     //驗證token是否過期
54     private Boolean isTokenExpired(String token) {
55         final Date expiration = getExpirationDateFromToken(token);
56         return expiration.before(new Date());
57     }
58 
59     //根據用戶生成token
60     public String generateToken(UserDetails userDetails) {
61         Map<String, Object> claims = new HashMap<>();
62         return doGenerateToken(claims, userDetails.getUsername());
63     }
64 
65     //生成token
66     private String doGenerateToken(Map<String, Object> claims, String subject) {
67         return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
68                 .setExpiration(new Date(System.currentTimeMillis() + (tokenValidity * 1000)))
69                 .signWith(SignatureAlgorithm.HS512, secret).compact();
70     }
71 
72     //驗證token
73     public Boolean validateToken(String token, UserDetails userDetails) {
74         final String userName = getUsernameFromToken(token);
75         return (userName.equals(userDetails.getUsername()) && !isTokenExpired(token));
76     }
77 
78 }
tokenValidity這個token有效期和secret加密秘鑰,這兩個變量是通過讀取spring boot的application.yml配置文件中定義的,在spring Ioc容器實例化這個類的實例的時候就會從配置文件中讀取,這樣不寫死,也方便后續修改
到這里關於jwt的代碼實現其實已經結束了,已經可以生成token,和驗證token了,接下來就是關於spring security的配置部分了,其實spring security相比於另外一個安全框架shiro來說絕對算是重量級,也比較復雜,但是呢由於是spring提供,搭配整個spring生態使用應該還是可以的
首先spring security對用戶的操作,比如登錄判斷用戶名密碼是否正確,訪問某個資源是否有對應的權限,定義了一個接口 或許也有類吧 但是我是實現了接口 重寫了那些方法 就算是滿足了spring security要求的安全用戶對象,在它內部的實現機制就會用到,我們只需要傳參構建好這個對象即可
 1 import org.springframework.security.core.GrantedAuthority;
 2 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 3 import org.springframework.security.core.userdetails.UserDetails;
 4 
 5 import java.util.Collection;
 6 import java.util.List;
 7 import java.util.stream.Collectors;
 8 
 9 /**
10  * @Description: 實現 UserDetails 重寫方法 就是滿足spring security安全要求的用戶
11  *               spring security驗證用戶必須要使用實現UserDetails的類,的實例
12  *               所以構建這個類 將我們自身實體類中的一些字段 賦值到這個類 用於校驗
13  *               也是由於我們自身的用戶實體類 字段比較多
14  * @Author: Tan
15  * @CreateDate: 2019/12/6
16  **/
17 public class SecurityUser implements UserDetails {
18     //用戶名
19     private String userName;
20     //密碼
21     private String passWord;
22     //權限集合
23     private  Collection<? extends GrantedAuthority> authoritys;
24     //是否可用
25     private  boolean enabled;
26 
27     /**
28      * @Description:  這個構造方法  從用戶實體對象中給這個安全用戶賦值
29      * @Author: Tan
30      * @Date: 2019/12/6
31      * @param userName: 用戶賬號
32      * @param passWord:  用戶密碼
33      * @param authority:  用戶權限集合
34      * @param enabled:  用戶是否可用
35      * @return: null
36      **/
37     public SecurityUser (String userName, String passWord, List<String> authority,boolean enabled ){
38         this.userName=userName;
39         this.passWord=passWord;
40         this.enabled=enabled;
41         this.authoritys =authority.stream().map(item->new SimpleGrantedAuthority(item)).collect(Collectors.toList());
42     }
43 
44     @Override
45     public Collection<? extends GrantedAuthority> getAuthorities() {
46         return this.authoritys;
47     }
48 
49     @Override
50     public String getPassword() {
51         return this.passWord;
52     }
53 
54     @Override
55     public String getUsername() {
56         return this.userName;
57     }
58 
59     @Override
60     public boolean isAccountNonExpired() {
61         return true;
62     }
63 
64     @Override
65     public boolean isAccountNonLocked() {
66         return true;
67     }
68 
69     @Override
70     public boolean isCredentialsNonExpired() {
71         return true;
72     }
73 
74     @Override
75     public boolean isEnabled() {
76         return this.enabled;
77     }
78 }

這個類只定義了用戶名,密碼,擁有的權限和是否可用,其實還可以定義幾個屬性,比如該用戶是否未鎖定,是否未過期,密碼是否未過期,這里我就沒有寫了 在重寫的方法里面默認返回都是true,這個類寫好了,在別的地方會實例化的.

其實為什么不使用和數據庫對應的User實體類來實現這個接口,因為和數據庫對應的User實體類肯定是有很多無關的字段,所以還是單獨建一個類,將用戶名,密碼這些值傳進來進行構建比較好.

接下來編寫一個類實現一個接口重寫一個方法,后續spring security框架會將得到的用戶名調用這個方法,我們可以在這個方法里面將得到的用戶名去數據庫查詢出是否有對應的記錄,如果有記錄就構建上面這個類的對象,傳入用戶名,密碼,權限集合,是否可用然后返回

如果不存在這個記錄,直接拋出一個用戶名不存在異常 UsernameNotFoundException,我們這里返回了一個有用戶名,密碼,權限集合的對象,如果是登錄的話,spring security框架會將這個用戶名密碼和從請求里面得到的token中解析出來的用戶進行匹配 如果匹配失敗

就會響應401錯誤,把代碼貼出來

 1 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 2 import com.tqq.eggchat.dao.UserMapper;
 3 import com.tqq.eggchat.entity.SecurityUser;
 4 import com.tqq.eggchat.entity.User;
 5 import lombok.extern.slf4j.Slf4j;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.security.core.userdetails.UserDetails;
 8 import org.springframework.security.core.userdetails.UserDetailsService;
 9 import org.springframework.security.core.userdetails.UsernameNotFoundException;
10 import org.springframework.stereotype.Service;
11 
12 import java.util.Arrays;
13 
14 /**
15  * @Description: 這個類實現UserDetailsService接口 成為滿足spring security標准的用戶業務類
16  *               提供根據用戶名 返回 UserDetails對象的方法
17  *               這里可以注入dao類對象 查詢數據庫 對應的用戶信息 然后構造UserDetails對象
18  * @Author: Tan
19  * @CreateDate: 2019/12/6
20  **/
21 @Slf4j
22 @Service
23 public class SecurityService implements UserDetailsService {
24 
25     @Autowired
26     private UserMapper userMapper;
27 
28     /**
29      * @Description: 根據用戶名去數據庫查詢對應的用戶信息
30      * @Author: Tan
31      * @Date: 2019/12/6
32      * @param userName: 用戶名
33      * @return: org.springframework.security.core.userdetails.UserDetails
34      **/
35     @Override
36     public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
37         //根據用戶名查詢用戶信息
38         User user = userMapper.selectOne(new QueryWrapper<User>().eq("s_account", userName));
39         if(user!=null){
40             //這里暫時沒有權限的概念 就默認個user權限
41             return new SecurityUser(user.getS_account(),user.getS_password(), Arrays.asList("USER"),user.getI_status()==1?true:false);
42         }else{
43             log.info("查詢數據庫,該賬號{}不存在",userName);
44             throw  new UsernameNotFoundException(String.format("%s 該賬號不存在",userName));
45         }
46     }
47 }

我這個@Slf4j是lombok框架提供的一個功能,相當於是一個日志對象,省得重復寫了,直接在代碼中就可以用,在編譯以后會加上的.要想使用這個功能除了要引用lombok框架的依賴,使用的IDE也要裝插件才能使用

客戶端每次請求都會帶上token.那么就需要一個過濾器,從請求對象中獲取token 然后進行解析等,把過濾器代碼貼出來

 1 /**
 2  * @Description: 這個過濾器用於判斷請求中是否有token 如果有就進行登錄到spring security中
 3  *               繼承OncePerRequestFilter 這個類是spring 對filter的封裝 可以實現
 4  *               一次請求 只會執行一次過濾器
 5  * @Author: Tan
 6  * @CreateDate: 2019/12/6
 7  **/
 8 @Component
 9 public class JwtRequestFilter extends OncePerRequestFilter {
10 
11     @Autowired
12     private SecurityService securityService;
13 
14     @Autowired
15     private JwtTokenUtil jwtTokenUtil;
16 
17     @Override
18     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
19             String tokenHead=request.getHeader("Authorization");
20             //token頭不等於空 並且以Bearer 開頭進行token驗證登錄處理
21             if(tokenHead!=null&&tokenHead.startsWith("Bearer ")){
22                 //從請求頭中截取token
23                 String token=tokenHead.substring(7);
24     //通過token得到用戶名  如果token已過期或者錯誤 會拋出異常,並被spring security捕獲 調我們自定義的登錄失敗處理方法
25         String userName = jwtTokenUtil.getUsernameFromToken(token);
26         //用戶名不等於空  並且當前上下文環境中沒有認證過 就進行登錄驗證
27         if(userName!=null&& SecurityContextHolder.getContext().getAuthentication()==null){
28             //通過用戶名查詢數據庫 構建符合spring security要求的安全用戶對象
29             UserDetails userDetails = securityService.loadUserByUsername(userName);
30             //驗證token和用戶對象
31             if(jwtTokenUtil.validateToken(token,userDetails)){
32                 //通過安全用戶對象 構建一個登錄對象
33                 UsernamePasswordAuthenticationToken login=new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
34                 //傳入當前http請求對象
35                 login.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
36                 //將登錄對象 寫入到當前上下文環境中 后續的判斷 權限控制就由spring Security做
37                 SecurityContextHolder.getContext().setAuthentication(login);
38     }
39             //調用下一個過濾器  如果有token已經在此完成登錄 沒有登錄的話 會被后續攔截器處理
40             filterChain.doFilter(request,response);
41     }
42 
43 }

在這個過濾器里面有注入了操作jwt的工具類和之前定義的用於根據用戶名查詢數據庫構建spring security要求的用戶對象的類,

過濾器寫好以后,怎么樣使用,並且安全框架實現認證攔截控制都是通過,過濾器來實現的,過濾器一般都是一個鏈,我們這個截取token完成解析登錄,就必須要在spring security所有過濾器之前,而且由於我們這個是spring boot項目已經拋棄了xml配置文件

對於框架的配置全部采用配置類,在這個spring security配置類中可以配置那些資源或者url需要登錄,或者需要什么權限,這也是比較重要的一個類,我把代碼貼出來

 1  /**
 2  * @Description: spring security核心配置類 功能都在此配置
 3  * @Author: Tan
 4  * @CreateDate: 2019/12/8
 5  **/
 6 @EnableGlobalMethodSecurity(prePostEnabled = true)
 7 @EnableWebSecurity
 8 @Configuration
 9 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
10 
11      @Autowired
12      private SecurityService securityService;
13 
14      @Autowired
15      private JwtRequestFilter jwtRequestFilter;
16 
17      @Autowired
18      private UserLoginFailurceConfig userLoginFailurceConfig;
19 
20      @Autowired
21      private UserNotAuthorityConfig userNotAuthorityConfig;
22 
23 
24 
25     @Override
26     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
27             //配置密碼的加密方式
28         auth.userDetailsService(securityService).passwordEncoder(new BCryptPasswordEncoder());
29     }
30 
31     @Bean
32     @Override
33     public AuthenticationManager authenticationManagerBean() throws Exception {
34         //向spring容器中注入 認證管理器
35         return super.authenticationManagerBean();
36     }
37 
38     @Bean
39     public PasswordEncoder passwordEncoder(){
40         return new BCryptPasswordEncoder();
41     }
42 
43 
44 
45     @Override
46     protected void configure(HttpSecurity http) throws Exception {
47          //關閉csrf防護器
48         http.csrf().disable()
49                  //session管理器為無狀態
50                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
51                 .and()
52                 //登錄和注冊所有人可以訪問
53                 .authorizeRequests().antMatchers("/user/userLogin","/user/userRegister","/user/checkUserAccount").permitAll()
54                 //放行swagger2
55                 .antMatchers("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**").permitAll()
56                 //所有請求需要認證
57                 .anyRequest().authenticated()
58                 .and()
59                 //添加我們實現的過濾器到spring security過濾器鏈的第一個 進行過濾
60                 .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
61         //禁用緩存
62         http.headers().cacheControl();
63 
64         //設置異常處理  authenticationEntryPoint是身份驗證失敗的處理,accessDeniedHandler是沒有權限訪問處理
65         http.exceptionHandling().authenticationEntryPoint(userLoginFailurceConfig).accessDeniedHandler(userNotAuthorityConfig);
66     }
67 
68 
69 }

這里配置了那些url可以放行,還將前面寫的過濾器添加到了過濾鏈的第一個,並且還設置了兩個異常處理類,就是身份驗證失敗處理,和訪問沒有權限的資源處理,這兩個類呢主要是可以進行一些定制化的響應,比如和前端約定響應狀態碼為10003代表無權限訪問

這樣前端就可以重定向到指定的頁面,否則就都是403,把這個兩個異常處理類貼出來.

 1 /**
 2  * @Description: 當spring security驗證用戶身份失敗時 會調用 這個類的commence方法
 3  *               有兩種情況 第一張用戶名密碼錯誤  第二種 就是token過期或者錯誤
 4  * @Author: Tan
 5  * @CreateDate: 2019/12/14
 6  **/
 7 @Component
 8 public class UserLoginFailurceConfig implements AuthenticationEntryPoint {
 9     @Override
10     public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
11 
12         //將自定義響應結果轉json字符串 默認是用戶名密碼錯誤的提示信息
13         String resultJsonString = JSONUtil.toJsonStr(ResponseResult.failure(ResponseCodeEnum.USER_LOGIN_ERROR));
14 
15 
16         //從請求對象中獲取token
17         String tokenHead = httpServletRequest.getHeader("Authorization");
18         //如果token不是空  並且Bearer 開頭 那么就是token錯誤或者過期了
19         if(tokenHead!=null&&tokenHead.startsWith("Bearer ")){
20             //將token錯誤或過期提示 轉換成字符串
21              resultJsonString = JSONUtil.toJsonStr(ResponseResult.failure(ResponseCodeEnum.USER_TOKEN_ERROR));
22             //設置響應對象狀態碼
23             httpServletResponse.setStatus(ResponseCodeEnum.USER_TOKEN_ERROR.getCode());
24         }
25 
26         //設置響應內容類型
27         httpServletResponse.setContentType("application/json;charset=utf-8");
28         //輸出結果
29         httpServletResponse.getWriter().print(resultJsonString);
30     }
31 }

其實重寫的這個方法就和servlet里面的那個doPost差不多,調用的時候,會把請求和響應對象都給你傳進來,你寫你自己的邏輯即可,其實通過重寫這個類,我就可以響應前端,這次到底是用戶名密碼錯誤還是token過期或者錯誤,如果不寫則都是401響應

把沒有權限訪問的類也貼出來

 1 /**
 2  * @Description: 用戶已登錄 請求沒有權限的接口 響應信息
 3  * @Author: Tan
 4  * @CreateDate: 2019/12/14
 5  **/
 6 @Component
 7 public class UserNotAuthorityConfig implements AccessDeniedHandler {
 8     @Override
 9     public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
10         //將自定義響應結果轉json字符串 默認是用戶名密碼錯誤的提示信息
11         String resultJsonString = JSONUtil.toJsonStr(ResponseResult.failure(ResponseCodeEnum.USER_NOT_AUTHORITY));
12 
13         //設置響應對象狀態碼
14         httpServletResponse.setStatus(ResponseCodeEnum.USER_NOT_AUTHORITY.getCode());
15 
16         //設置響應內容類型
17         httpServletResponse.setContentType("application/json;charset=utf-8");
18         //輸出結果
19         httpServletResponse.getWriter().print(resultJsonString);
20     }
21 }

到這里基本上spring security整合jwt基本上完了  還要講一下權限控制,在SecurityService這個類的loadUserByUsername方法中,查詢數據庫然后構建SecurityUser這個對象,可以傳入這個所擁有的權限集合,這個集合一般也是查詢數據庫查出來

這里默認都是使用spring mvc 那么在對應的controller類上的方法上可以加一個注解 @PreAuthorize("權限名")  那么當請求這個方法的url地址時,spring security會判斷是否登錄,已登錄后是否擁有該權限.這樣就實現了權限控制

這里還要單獨講一下登錄和注冊方法,我把service類方法貼出來

 1   /**
 2  * @Description: 用戶服務類
 3  * @Author: Tan
 4  * @CreateDate: 2019/12/8
 5  **/
 6 @Service
 7 public class UserServiceImpl implements UserService {
 8 
 9     @Autowired
10     private UserMapper userMapper;
11 
12     @Autowired
13     private JwtTokenUtil jwtTokenUtil;
14 
15     @Autowired
16     private AuthenticationManager authenticationManager;
17 
18     @Autowired
19     private SecurityService securityService;
20 
21 
22     @Override
23     public User userRegister(User user) {
24         if(user.getS_account()!=null){
25             BCryptPasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
26             user.setS_password(passwordEncoder.encode(user.getS_password()));
27             user.setD_register_date(new Date());
28             int insert = userMapper.insert(user);
29             return insert==1?user:null;
30         }
31         return null;
32     }
33 
34     @Override
35     public String userLogin(String userName, String passWord) {
36         //根據輸入的用戶名和密碼創建一個 用戶名密碼token
37         UsernamePasswordAuthenticationToken userNamepassWordToken = new UsernamePasswordAuthenticationToken( userName, passWord );
38         //創建認證對象 傳入用戶名密碼token 然后spring security會根據用戶名去調用loadUserByUsername方法
39         //這個方法是由我們重寫了 是根據用戶名去數據庫查詢 只要查詢到記錄 交由spring security進行密碼比較
40         //如果沒有查詢到對應記錄 或者密碼不正確 就會直接響應403  這里后續代碼不會執行
41         Authentication authentication = authenticationManager.authenticate(userNamepassWordToken);
42         //執行到這一步 代表用戶名密碼已經校驗成功了 將認證對象寫入到spring security上下文環境中
43         SecurityContextHolder.getContext().setAuthentication(authentication);
44         //根據用戶名查詢結果 然后生成token 並返回
45         UserDetails userDetails = securityService.loadUserByUsername( userName );
46         return jwtTokenUtil.generateToken(userDetails);
47     }
48 
49 }
userRegister 這個方法是注冊 也沒什么特別的 接收了User對象以后使用BCryptPasswordEncoder對密碼進行加密,然后保存到數據庫,
userLogin   這個方法是登錄,首先將接收到的用戶名密碼構建成一個spring security框架定義的用戶名密碼token對象 然后根據這個對象去創建 Authentication這個對象,在創建這個對象時,會通過傳入用戶名密碼token對象得到用戶名然后去調用我們之前那個loadUserByUsername方法
從數據庫查詢構建出一個對象來進行比較,如果比較失敗就會是登錄失敗會調用前面寫的登錄失敗處理類,這個方法里面的后續代碼也不會執行了.還有一點就是如果同一個用戶多次登錄 每次生成的token都不會相同,因為token里面包含了時間信息,后續也是通過解析token來判斷是否過期



三丶 總結

看了前面這一大堆,這么多類 方法 可能會對整個執行流程很懵,這里我在結合我的理解說一下我認為的整個執行流程,可能不對,歡迎指正.

首先如果你是請求登錄的url,最開始先進入到上面的JwtRequestFilter這個過濾器,先判斷你的請求是否有token,如果你的請求攜帶了token,並且對token的進行解析校驗,沒問題就會登錄到spring security的上下文中,然后調用下一個過濾器,我覺得spring security剩下的過濾器都會
判斷上下文中是否已登錄,如果已登錄都會放行調用下一個過濾器直到調用到要訪問的url.如果你沒有攜帶token,並且你訪問的url是需要登錄的,那么你就會被攔截. 這是關於登錄的

如果是權限管理,在解析token進行登錄,或者有用戶名密碼進行登錄都會調用SecurityService類重寫的loadUserByUsername方法,在這個方法里面我們可以查詢數據庫中這個用戶的信息,並且也可以查詢這個用戶所擁有的權限,生成一個String類型的集合,然后構建一個我們自定義的類實現了
spring security要求的用戶對象給spring security進行認證和判斷是否有權限,然后具體某個controller的方法,只需要加上@PreAuthorize("權限名") 注解 剩下的判斷交由spring security即可

其實關於前端的部分我就沒有寫出來了,我前端使用的是vue,vue中請求統一都是用axios,axios可以配置兩個攔截器,請求攔截器和響應攔截器,在發請求的時候可以帶上token,響應攔截器里面可以判斷后台響應值對頁面進行跳轉,比如后台沒有登錄會響應一個什么狀態碼,在響應攔截器里面判斷如果是
這個狀態碼就操作路由跳轉頁面啥的

大致差不多就這樣吧 網上看了很多關於spring security整合jwt的 很多方法 我這個是我自己參考了別人的文章 和我自己慢慢嘗試的 后續有更多在補充吧

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM