SpringSecurity學習記錄4
技術標籤:SpringSecurity
2.12 RememberMe功能實現
Spring Security 中Remember Me為“記住我” 功能,使用者只需要在登入時新增 remember me 複選框,取值為 true Spring Security會自動把使用者資訊儲存到資料來源中,以後就可以不登入進行訪問。
新增依賴
Spring Security 實 現 Remember Me 功 能 時 底 層 實 現 依 賴Spring-JDBC,所以需要匯入 SpringJDBC。以後多使用 MyBatis 框架而很少直接匯入 spring-jdbc,所以此處匯入 mybatis 啟動器同時還需 要新增 MySQL 驅動
<!-- mybatis 依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- mysql 資料庫依賴 -->
<dependency>
<groupId>mysql</ groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
配置資料來源
在 application.properties 中配置資料來源。請確保資料庫中已經存在shop資料庫
spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver spring.datasource.url= jdbc:mysql://localhost:3306/security? useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai spring.datasource.username= root spring.datasource.password= root
編寫配置
RememberMeConfig.java
package com.xxxx.springsecuritydemo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;
/**
* @author zhoubin
* @since 1.0.0
*/
@Configuration
public class RememberMeConfig {
@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository getPersistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new
JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//自動建表,第一次啟動時需要,第二次啟動時註釋掉
jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
}
修改SecurityConfig.java
在SecurityConfig中新增RememberMeConfig和UserDetailsService實現類物件,並自動注入。 在 configure 中新增下面配置內容。
http.rememberMe()
//登入邏輯交給哪個物件
.userDetailsService(userService)
// 持久層物件
.tokenRepository(persistentTokenRepository);
在客戶端頁面新增複選框
在客戶端登入頁面中新增 remember-me 的複選框,只要使用者勾選了複選框下次就不需要進行登入了。
<form action="/login" method="post">
使用者名稱:<input type="text" name="username" /><br/>
密碼:<input type="password" name="password" /><br/>
<input type="checkbox" name="remember-me" value="true"/><br/>
<input type="submit" value="登入" />
</form>
有效時間
啟專案後登入狀態失效了。但是可以通過設定狀態有效時間,即使專案重新啟動下次也可 以正常登入。
http.rememberMe()
//失效時間,單位秒
.tokenValiditySeconds(120)
//登入邏輯交給哪個物件
.userDetailsService(userService)
// 持久層物件
.tokenRepository(persistentTokenRepository);
2.13 退出登入
使用者只需要向 Spring Security 專案中傳送 /logout 退出請求即可。
實現退出非常簡單,只要在頁面中新增 /logout 的超連結即可。
<a href="/logout">退出登入</a>
為了實現更好的效果,通常新增退出的配置。預設的退出 url 為 /logout ,退出成功後跳轉到 /login? logout
如果不希望使用預設值,可以通過下面的方法進行修改。
http.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login.html");
2.14 SpringSecurity中的CSRF
從剛開始學習Spring Security時,在配置類中一直存在這樣一行程式碼: http.csrf().disable(); 如 果沒有這行程式碼導致使用者無法被認證。這行程式碼的含義是:關閉 csrf 防護。
什麼是CSRF
CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“OneClick Attack” 或者 Session Riding。通過偽造使用者請求訪問受信任站點的非法請求訪問。 跨域:只要網路協議,ip 地址,埠中任何一個不相同就是跨域請求。 客戶端與服務進行互動時,由於 http 協議本身是無狀態協議,所以引入了cookie進行記錄客戶端身 份。在cookie中會存放session id用來識別客戶端身份的。在跨域的情況下,session id 可能被第三方 惡意劫持,通過這個 session id 向服務端發起請求時,服務端會認為這個請求是合法的,可能發生很多 意想不到的事情。
2、Spring Security中的CSRF
從 Spring Security4開始CSRF防護預設開啟。預設會攔截請求。進行CSRF處理。CSRF為了保證不是 其他第三方網站訪問,要求訪問時攜帶引數名為 _csrf 值為token(token 在服務端產生)的內容,如果 token和服務端的token匹配成功,則正常訪問。
2.1、編寫控制器方法
編寫控制器方法,跳轉到 templates 中 login.html 頁面。
@RequestMapping("/showLogin")
public String showLogin(){
return "login";
}
2.2、新建login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<input type="hidden" th:value="${_csrf.token}" name="_csrf"
th:if="${_csrf}"/>
使用者名稱:<input type="text" name="username" /><br/>
密碼:<input type="password" name="password" /><br/>
<input type="submit" value="登入" />
</form>
</body>
</html>
修改配置類
在配置類中註釋掉 CSRF 防護失效
//關閉csrf防護
// http.csrf().disable();