SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity進行前后端分離的登錄驗證


 

1 SpirngBoot環境搭建

  創建一個SpringBoot項目即可,詳情參見三少的相關博文

  參考博文 -> 點擊前往

  SpirngBoot項目腳手架 -> 點擊前往

 

2 引入SpirngSecurity依賴

  技巧01:引入了springSecurity相關依賴后,項目就會被SpringSecurity進行管理了;默認的登錄名為user,登錄密碼會被打印到控制台上

  技巧02:SpringSecurity默認的配置使用的是

        <!--spring-security相關-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

  2.1 啟動項目

    技巧01:每次啟動項目所打印出來的密碼都是不一樣的

    控制台打印的登錄密碼信息如下:

      

  2.2 請求一個后台實現的RestfulAPI

    技巧01:項目啟動后,前台首次訪問時都會被重定向到一個默認的登錄頁面

    技巧02:springSecurity默認的配置時使用表單進行登錄

    技巧03:前后端分離時也是使用表單登錄,而且表單的用戶名必須是username,密碼必須是password(PS: 前后端分離時只需要模擬出表單提交請求即可,即:請求路徑對應,請求參數和后台對應即可)

      

  2.3 錄入信息

    技巧01:如果用戶名不是user或者密碼不是控制台打印的信息,都不會通過驗證

    技巧02:如果登錄信息成功后,SpringSecurity會默認重定向到之前訪問的路徑

    技巧03:前后端分離時要求登錄驗證無論成功與否都是返回JSON格式的數據,具體怎么跳轉有前端進行控制

      

 

3 SpirngSecurity基礎配置

  技巧01:自定義SpringSecurity時需要重寫一個UserDetaiService類,而該類需要使用一個對密碼進行加密和解密的工具類,所以我們需要在自定義的SpringSecurity配置文件中指定這個密碼加密解密工具的類的Bean,使得這個類會被Spring容器管理

package cn.test.demo.base_demo.config.springSecurity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author 王楊帥
 * @create 2018-05-27 21:27
 * @desc
 **/
@Configuration
public class FurySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /** 依賴注入自定義的登錄成功處理器 */
    @Autowired
    private FuryAuthenticationSuccessHandler furyAuthenticationSuccessHandler;

    /** 依賴注入自定義的登錄失敗處理器 */
    @Autowired
    private FuryAuthenticationFailureHandler furyAuthenticationFailureHandler;

//    向spring容器中創建一個Bean
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http.formLogin()
//                .loginProcessingUrl("/login")
//                .successHandler(furyAuthenticationSuccessHandler)
//                .failureHandler(furyAuthenticationFailureHandler)
//                .and().authorizeRequests()
//                        .antMatchers("/login").permitAll()
//                        .anyRequest()
//                        .authenticated()
//                .and().csrf().disable();
//    }
}
View Code

  參考博文 -> 點擊前往

   

4 繼承UserDetaiService

  繼承UserDetaiService的子類可以實現登錄用戶驗證以及登錄用戶的權限查詢

package cn.test.demo.base_demo.config.springSecurity;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @author 王楊帥
 * @create 2018-05-27 21:23
 * @desc
 **/
@Component
@Slf4j
public class FuryUserDetailService implements UserDetailsService {

    /**
     * 依賴注入密碼加密解密工具(PS: 需要在springsecurity的配置文件中配置這個Bean)
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 打印前端傳過來的用戶數據
        log.info("前端闖過來的用戶名為:{}", username);

        // 模擬數據庫中的數據
        String pwd = passwordEncoder.encode("111");

        // 返回一個User對象(技巧01:這個User對象的密碼是從數據庫中取出來的密碼)
//      // 技巧02:數據庫中的密碼是在創建用戶時將用戶的密碼利用SpreingSecurity配置中相同的密碼加密解密工具加密過的
        return new User(username, pwd, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}
View Code

  參考博文 -> 點擊前往

   4.1 測試

    重啟項目后,訪問一個RestfulAPI時;控制台就不會再打印出密碼信息了,繼承UserDetaiService的子類會接收到前端傳過來的用戶名和密碼,我們可以在繼承UserDetaiService的子類中依賴注入先關的持久層來通過用戶名到數據庫中去查詢用戶密碼,在將查到的密碼和用戶登錄時的密碼進行比對,從而判斷用戶登錄驗證是否成功;還可以根據用戶名到數據庫中去查詢該用戶的權限信息

    技巧01:此時用戶名可以隨便輸入

    技巧02:由於密碼是三少在后台進行硬編碼的的,所以登錄時密碼必須是 “111”(即:用戶名任意,密碼只要是 111 就可以登錄成功,否則就會登錄失敗)

 

6 前后端分離配置

  參考博文 -> 點擊前往

  需求01:修改表單的登錄路徑

    》配置登錄請求路徑即可

  需求01:無論登錄驗證成功與否都返回JSON格式字符串

  技巧01:以上的需求都可以在自定義的SpringSecurity配置中實現

  技巧02:前后端分離時,請求的方式必須是POST方式,而且必須傳遞username和password兩個變量到后台

  6.1 驗證后的JSON格式返回

    只需要分別實現兩個處理接口即可:AuthenticationSuccessHandler、AuthenticationFailureHandler;這兩個接口分別處理登錄驗證成功和失敗

package cn.test.demo.base_demo.config.springSecurity;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 王楊帥
 * @create 2018-05-27 21:48
 * @desc
 **/
@Slf4j
@Component
public class FuryAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper; // Json轉化工具

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登錄驗證成功");
        response.setContentType("application/json;charset=UTF-8"); // 響應類型
        response.getWriter().write(objectMapper.writeValueAsString("登錄驗證成功"));
    }
}
FuryAuthenticationSuccessHandler.java
package cn.test.demo.base_demo.config.springSecurity;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 王楊帥
 * @create 2018-05-27 21:55
 * @desc
 **/
@Component
@Slf4j
public class FuryAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("登錄驗證失敗");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(exception));;
    }
}
FuryAuthenticationFailureHandler.java

  6.2 配置自定SpringSecurity配置

package cn.test.demo.base_demo.config.springSecurity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author 王楊帥
 * @create 2018-05-27 21:27
 * @desc
 **/
@Configuration
public class FurySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /** 依賴注入自定義的登錄成功處理器 */
    @Autowired
    private FuryAuthenticationSuccessHandler furyAuthenticationSuccessHandler;

    /** 依賴注入自定義的登錄失敗處理器 */
    @Autowired
    private FuryAuthenticationFailureHandler furyAuthenticationFailureHandler;

//    向spring容器中創建一個Bean
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginProcessingUrl("/furyLogin") // 登錄請求路徑
                .successHandler(furyAuthenticationSuccessHandler) // 驗證成功處理器
                .failureHandler(furyAuthenticationFailureHandler) // 驗證失敗處理器
                .and().authorizeRequests()
                        .antMatchers("/furyLogin").permitAll() // 登錄請求路徑不進行過濾
                        .anyRequest()
                        .authenticated()
                .and().csrf().disable(); // 取消跨站請求偽造防護
    }

}
View Code

  6.3 測試

    利用postman進行測試

    技巧01:只需要模擬出 登錄請求即可;POST請求,參數分別是username和password

    坑01:雖然在springSecurity的自定義配置文件中配置的登錄請求路徑是 /furyLogin ,但是我們在模擬的時候必須模擬 http://127.0.0.1:9999/dev/furyLogin,因為必須加上IP、端口和應用上下文路徑

    6.3.1 登錄驗證失敗的效果展示

      

    6.3.2 登錄成功的效果

      

  案例源代碼 -> 點擊前往

 

7 利用Angular實現前端登錄

 

8 登錄成功后返回對應的菜單信息

 

9 權限問題

 

 

·下面是我的公眾號二維碼,歡迎關注·

尋渝記

微信號:xyj_fury

 


免責聲明!

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



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