1.引入Bcrypt工具類,這個類裏有。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
這個包只要你開始引入那麼整個項目特麼多是不能訪問的!
有什麼辦法呢?放開攔截就解決這個問題了!因爲我們使用這個類也是因爲這個jar包特麼的擁有Bcrypt工具類!
怎麼放開呢?
創建下面這個類必須是跟Spring boot啓動文件放在一級!
@Configuration //告訴項目這是個配置文件早點加載
@EnableWebSecurity //以實現Web安全性
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{//基類是個牛逼的類包含了很多涉及安全要使用的方法比如下面個重寫的方法!
//下面這個方法簡單的可以理解放開所有攔截!詳細自己查!
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
}
2.在Spring boot項目中的
Application啓動類中添加一個加密工具類。如下
@Bean
prublic BcryptPasswordEncoder encoder(){
return new BcryptPasswordEncoder();
}
上面這個方法主要就是編寫這個工具類加載到項目的容器中,那麼加密的工具類算是解決了!
下面簡單的操作下怎麼使用這個類來實現用戶密碼的加密和登錄時候的驗證!
@Autowired
private BcryptPasswordEncode encoder;
public void add(Admin admin){
//先是加密
String newpass=encoder.encoder(admin,getPassword());//加密後的密碼
}
public void login(Map<String,String> map){
String loginname=map.get("name");
User user=userService.findLoginname(loginname);
if(user!=null && encode.matches(map.get("password"),user.getPassword)){//參數1是當前用戶登錄的密碼,參數2是數據庫的加密數
println("吊毛登錄成功密碼正確");
}else{
println("吊毛登錄密碼錯誤!");
}
}
看到這個圖應該懂matches()方法怎麼驗證新舊密碼了!
接下來講講流行的權限驗證!
Token Auth:
1. 客戶端使用用戶名跟密碼請求登錄
2. 服務端收到請求,去驗證用戶名與密碼
3. 驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
4. 客戶端收到 Token 以後可以把它存儲起來,比如放在 Cookie 裏
5. 客戶端每次向服務端請求資源的時候需要帶着服務端簽發的 Token
6. 服務端收到請求,然後去驗證客戶端請求裏面帶着的 Token,如果驗證成功,就向
客戶端返回請求的數據
token機制相比較Cookie機制的優點有以下幾點!
1.支持跨域訪問:Cookie是不允許垮域訪問的,這一點對Token機制是不存在的,前提
是傳輸的用戶認證信息通過HTTP頭傳輸
2.無狀態(也稱:服務端可擴展行):Token機制在服務端不需要存儲session信息,因爲
Token 自身包含了所有登錄用戶的信息,只需要在客戶端的cookie或本地介質存儲
狀態信息.
3.CSRF:因爲不再依賴於Cookie,所以你就不需要考慮對CSRF(跨站請求僞造)的防
範
下面講講怎麼生成這麼優秀的token:
基於JWT的token認證機制實現!
然而有個問題就是JWT是個啥!
它就是就是JSON WEB TOKEN(JWT)是一個輕巧的規範!可以利用這個規範來回於客戶端和服務器之間傳遞信息!
JWT的組成:
一個規範的JWT其實就是一個很長的字符串!但是它由三部分生成!頭部(Header),載荷還有簽名。
頭部(Header)
用於描述基本的JWT信息,列如其類型,以及簽名的算法。
{"typ":"jwt","alg":"HS256"}
可以去這個網站嘗試下:http://tool.oschina.net/encrypt/
載荷(playload)
這個呢就是存放有效的信息,有效信息包含三個部分!
(1)標準中註冊的聲明
iss: jwt簽發者
sub: jwt所面向的用戶
aud: 接收jwt的一方
exp: jwt的過期時間,這個過期時間必須要大於簽發時間
nbf: 定義在什麼時間之前,該jwt都是不可用的.
iat: jwt的簽發時間
jti: jwt的唯一身份標識,主要用來作爲一次性token,從而回避重放攻擊
(2)公共的聲明
可以添加任何信息,一般就是添加用戶相關的信息,或是其他一些必要的信息。這部分在客戶端是可以解密的!
(3)私有的聲明
這個是生產者和消費者所共同定義的聲明,一般不建議存放小祕密,base64是解密的。
這個指的就是自定義的claim。比如前面那個結構舉例中的admin和name都屬於自定的
claim。這些claim跟JWT標準規定的claim區別在於:JWT規定的claim,JWT的接收方在
拿到JWT之後,都知道怎麼對這些標準的claim進行驗證(還不知道是否能夠驗證);而
private claims不會驗證,除非明確告訴接收方要對這些claim進行驗證以及規則才行。
定義個載荷:(payload )
{"sub":"1234567890","name":"John Doe","admin":true}
然後進行編碼得到JWT的第二部分:
U2FsdGVkX1+cUgHYwPAxxcIVZic0nHS4NaJ/OvqQ4ECoTyQOKxK75NV2txe25qyz
8YMjvKNpwZyaK6/m6cZy3UugCh+XQKnqkZbdCNDBdmI=
簽證(signature)
這個部分需要base64加密後的header和base64加密後的payload使用.連接組成的字符
串,然後通過header中聲明的加密方式進行加鹽secret組合加密,然後就構成了jwt的第
三部分.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
將這三部分用.連接成一個完整的字符串,構成了最終的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6I
kpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7Hg
Q
secret(可以理解成祕鑰)是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用
來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流
露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了。
下面講講怎麼使用Java實現JWT,那就是JJWT
問題來了什麼是JJWT呢?
其實就是一個提供客戶端到服務端的JWT創建和驗證的JAVA庫。
在項目中如何使用呢?
在maven工程中引入依賴
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
下面這段代碼測試下:
public class CreateJwtTest { public static void main(String[] args) {
JwtBuilder builder= Jwts.builder().setId("123") .setSubject("小菜鳥") .setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256,"ousuhao"); System.out.println( builder.compact() );
} }
輸出的內容是:jsonwebtoken.impl.DefaultJwtBuilder@5c7fa833
每次生成的都不一樣,因爲載荷裏面加了當前的時間。
講了生成token,那麼下面講講怎麼解析,因爲在web應用中這個操作是由服務端進行然後發給客戶端的,下次客戶端要想訪問就要提供token.那麼服務端接到這個token應該接解析出token中的用戶id,根據用戶id查詢用戶相關的詳細數據。
下面是解析代碼!
public class ParseJwtTest { public static void main(String[] args) { String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjMiLCJzdWIiOiLlsI_oj5zpuJ8iLCJpYXQiOjE1NTE3NjMxMzl9.DoKFDkgvNX3WR7cRv9bSfBq9LB6hdBSLqEIWIyGLlDs"; Claims claims=Jwts.parser().setSigningKey("ousuhao").parseClaimsJws(token).getBody(); System.out.println("id"+claims.getId()); System.out.println("subject"+claims.getSubject()); System.out.println("IssuedAt"+claims.getIssuedAt()); } }