日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

    歡迎訪問 生活随笔!

    生活随笔

    當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

    编程问答

    初识单点登录及JWT实现

    發(fā)布時間:2023/12/13 编程问答 23 豆豆
    生活随笔 收集整理的這篇文章主要介紹了 初识单点登录及JWT实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

    單點登錄

    多系統(tǒng),單一位置登錄,實現(xiàn)多系統(tǒng)同時登錄的一種技術

    (三方登錄:某系統(tǒng)使用其他系統(tǒng)的用戶,實現(xiàn)本系統(tǒng)登錄的方式。如微信登錄、支付寶登錄)

    單點登錄一般是用于互相授信的系統(tǒng),實現(xiàn)單一位置登錄,全系統(tǒng)有效

    ?

    一、Session跨域

      所謂 Session 跨域就是摒棄了系統(tǒng)提供的 Session ,而使用自定義的類似 Session 的機制來保存客戶端數(shù)據(jù)的一種解決方案。

      如:通過設置 cookie 的 domain 來實現(xiàn) cookie 的跨域傳遞。在 cookie 中傳遞一個自定義的 session_id。這個 session_id 是客戶端的唯一標記,將這個標記作為key,將客戶需要保存的數(shù)據(jù)作為value,在服務端進行保存(數(shù)據(jù)庫保存或nosql保存)。這種機制就是 Session 的跨域解決。

      什么為跨域:客戶端請求的時候,請求的服務器,不是同一個IP、端口、域名、主機名的時候,都稱為跨域。

      什么是域:在應用模型中,一個完整的、有獨立訪問路徑的功能集合成為一個域。

           如:百度稱為一個應用或系統(tǒng),其下有若干個域,如搜索引擎(www.baidu.com),百度貼吧(tie.baidu.com),百度知道(zhidao.baidu.com)等。

           有時也稱為多級域名。域的劃分:以IP、端口、域名、主機名為標準,實現(xiàn)劃分。

    ?

    二、Spring Session 共享

      spring-session 技術是 spring 提供的用于處理集群會話共享的解決方案。spring-session技術是將用戶 session 數(shù)據(jù)保存到第三方容器中,如數(shù)據(jù)庫。

      Spring-session 技術是解決同域名下的多服務器集群 session 共享問題的,不能解決跨域 Session 共享問題

    ?

    三、Nginx Session 共享

      nginx中的 ip_hash 技術能夠將某個 ip 的請求定向到同一臺后端,這樣一來這個ip下的某個客戶端和某個后端就能建立起穩(wěn)固的session,ip_hash是在upstream配置中定義的

    ?

    四、Token身份認證

      使用基于 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄,大概流程如下:

      1)客戶端使用用戶名、密碼請求登錄

      2)服務端收到請求、去驗證用戶名與密碼

      3)驗證成功后,服務端會簽發(fā)y一個 token ,再把這個 token 發(fā)送給客戶端

      4)客戶端收到 token 以后可以把它存儲起來,比如放在 cookie 里或者 Local Storage里

      5)客戶端每次向服務器請求資源的時候需要帶著服務器簽發(fā)的 token

      6)服務端收到請求,然后去驗證客戶端請求里面帶著的 token,如果驗證成功,就向客戶端返回請求的數(shù)據(jù)

      使用token的優(yōu)勢:

      無狀態(tài)、可擴展:

        在客戶端存儲的 token 是無狀態(tài)的,并且能夠被擴展,基于這種無狀態(tài)和不存儲session信息,負載均衡器能夠將用戶信息從一個服務傳到其他服務器上。

      安全性:

        請求中發(fā)送token而不再發(fā)送cookie能夠防止CSRF(跨域請求偽造)。即使在客戶端使用cookie存儲token。cookie也僅僅是一個存儲機制而不是用于認證。

      不將信息存儲在session中,讓我們少了對session的操作。

    ?

    五、JSON Web Token(JWT)機制

      JWT是一種緊湊且自包含的,用于在多方傳遞 json 對象的技術。傳遞的數(shù)據(jù)可以使用數(shù)字簽名增加其安全性??梢允褂肏MAC加密算法或RSA公鑰/私鑰加密方式。

      緊湊:數(shù)據(jù)小,可以通過URL、POST參數(shù),請求頭發(fā)送,且數(shù)據(jù)小代表傳輸速度快。

      自包含:使用 payload 數(shù)據(jù)塊j記錄用戶必要且不隱私的數(shù)據(jù),可以有效的減少數(shù)據(jù)庫訪問次數(shù),提高代碼性能

      JWT一般用于處理用戶身份校驗或數(shù)據(jù)信息交換

      JWT的數(shù)據(jù)結構

        JWT的數(shù)據(jù)結構:A.B.C  以.(點)來劃分

        A-header  頭信息

        B-payload  (有效荷載?)

        C-Signature  簽名

      header:

      數(shù)據(jù)結構:{"alg":"加密算法名稱","typ":"JWT"}

      alg可以有 HMAC 或 SHA256 或 RSA 等

      payload:主要分為三部分:已注冊信息、公開數(shù)據(jù)、私有數(shù)據(jù)

      singature:

        簽名信息,這是一個由開發(fā)者提供的信息。是服務器驗證的傳遞的數(shù)據(jù)是否有效安全的標準?! ?/p>

      執(zhí)行流程

      

    ?

    ?簡單實現(xiàn)

    1)造數(shù)據(jù) JWTUsers模擬數(shù)據(jù)庫用戶名密碼

    package cn.zytao.taosir;import java.util.HashMap; import java.util.Map;/*** 用于模擬用戶數(shù)據(jù)的,開發(fā)中應訪問數(shù)據(jù)庫驗證用戶* @author TAOSIR**/ public class JWTUsers {private static final Map<String,String> USERS =new HashMap<>(11);static {for(int i=0;i<10;i++) {USERS.put("admin"+i, "pwd"+i);}}//驗證是否可以登錄public static boolean isLogin(String username,String pwd) {if(null == username || username.trim().length()==0)return false;String obj=USERS.get(username);if(null ==obj||!obj.equals(pwd))return false;return true;} }

    2)JWTSubject

    package cn.zytao.taosir; /*** 作為Subject數(shù)據(jù)使用,也就是payload中保存的public claims* 其中不應包含任何敏感數(shù)據(jù)* 開發(fā)中建議使用實體類型,或BO,DTO數(shù)據(jù)對象* @author TAOSIR**/ public class JWTSubject {private String username;public JWTSubject() {super();}public JWTSubject(String username) {super();this.username = username;}public String getUsername() {return username;}public void setUsername(String username) {this.username=username;} }

    3)JWT結果對象

    package cn.zytao.taosir; /*** 作為Subject數(shù)據(jù)使用,也就是payload中保存的public claims* 其中不應包含任何敏感數(shù)據(jù)* 開發(fā)中建議使用實體類型,或BO,DTO數(shù)據(jù)對象* @author TAOSIR**/ public class JWTSubject {private String username;public JWTSubject() {super();}public JWTSubject(String username) {super();this.username = username;}public String getUsername() {return username;}public void setUsername(String username) {this.username=username;} }

    4)響應對象

    package cn.zytao.taosir;public class JWTResponseData {private Integer code;//返回碼private Object data;//業(yè)務數(shù)據(jù)private String msg;//返回描述private String token;//身份標識public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public String getToken() {return token;}public void setToken(String token) {this.token = token;} }

    5)JWT控制類

    package cn.zytao.taosir; /*** JWT工具類* @author TAOSIR**/import java.util.Date;import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec;import com.fasterxml.jackson.databind.ObjectMapper;import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureException;public class JWTUtils {private static final String JWT_SECERT = "test_jwt_secert";//服務器的key,密鑰private static final ObjectMapper MAPPER = new ObjectMapper();//用戶java對象和json字符串轉換public static final int JWT_ERRCODE_EXPIRE = 1005;//Token過期public static final int JWT_ERRCODE_FAIL = 1006;//驗證不通過public static SecretKey generalKey() {try {byte[] encodedKey=JWT_SECERT.getBytes("UTF-8");SecretKey key=new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;} catch (Exception e) {e.printStackTrace();return null;}}/*** 簽發(fā)JWT,即創(chuàng)建token的方法* @param id jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊* @param iss jwt簽發(fā)者* @param subject jwt所面向的用戶,payload中記錄的public,claims,當前環(huán)境中就是用戶的登錄名* @param ttlMills 有效期,單位毫秒* @return*/public static String createJWT(String id,String iss,String subject,long ttlMillis) {//加密算法SignatureAlgorithm signatureAlgorithm=SignatureAlgorithm.HS256;long nowMillis = System.currentTimeMillis();Date now=new Date(nowMillis);SecretKey secretKey=generalKey();//創(chuàng)建JWT的構造器用于生成tokenJwtBuilder builder=Jwts.builder().setId(id).setIssuer(iss).setSubject(subject).setIssuedAt(now).signWith(signatureAlgorithm, secretKey);if(ttlMillis >= 0) {long expMillis =nowMillis+ttlMillis;Date exDate = new Date(expMillis);builder.setExpiration(exDate);}return builder.compact();}/*** 驗證JWT* @param jwtStr* @return*/public static JWTResult validateJWT(String jwtStr) {JWTResult checkResult=new JWTResult();Claims claims=null;try {claims=parseJWT(jwtStr);checkResult.setSuccess(true);checkResult.setClaims(claims);} catch (ExpiredJwtException e) {checkResult.setSuccess(false);checkResult.setErrCode(JWT_ERRCODE_EXPIRE);} catch (SignatureException e) {checkResult.setSuccess(true);checkResult.setErrCode(JWT_ERRCODE_FAIL);}return checkResult;}/*** 解析JWT字符串* @param jwt 就是token* @return*/public static Claims parseJWT(String jwt) {SecretKey secretKey=generalKey();//getBody獲取值就是token中記錄的payload數(shù)據(jù),就是其中保存的claimsreturn Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}/*** 生成subject信息* @param subObj* @return*/public static String generalSubject(Object subObj) {try {return MAPPER.writeValueAsString(subObj);} catch (Exception e) {e.printStackTrace();return null;}} }

    6)寫個簡單的controller實踐

    package cn.zytao.taosir.controller;import java.util.UUID;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import cn.zytao.taosir.JWTResponseData; import cn.zytao.taosir.JWTResult; import cn.zytao.taosir.JWTSubject; import cn.zytao.taosir.JWTUsers; import cn.zytao.taosir.JWTUtils;@RestController public class JWTController {@RequestMapping("testAll")public Object testAll(HttpServletRequest request) {String token=request.getHeader("Authorization");JWTResult result=JWTUtils.validateJWT(token);JWTResponseData responseData=new JWTResponseData();if(result.isSuccess()) {responseData.setCode(200);responseData.setData(result.getClaims().getSubject());String newToken=JWTUtils.createJWT(result.getClaims().getId(), result.getClaims().getIssuer(), result.getClaims().getSubject(), 1*60*1000);responseData.setToken(newToken);return responseData;}else {responseData.setCode(500);responseData.setMsg("用戶未登錄");return responseData;}}@RequestMapping("login")public Object login(String username,String password) {JWTResponseData responseData=null;//認證用戶信息if(JWTUsers.isLogin(username, password)) {JWTSubject subject=new JWTSubject(username);String jwtToken = JWTUtils.createJWT(UUID.randomUUID().toString(),"sxt-test-jwt", JWTUtils.generalSubject(subject), 1*60*1000);responseData=new JWTResponseData();responseData.setCode(200);responseData.setData(null);responseData.setMsg("登錄成功");responseData.setToken(jwtToken);}else {responseData=new JWTResponseData();responseData.setCode(500);responseData.setData(null);responseData.setMsg("登錄失敗");responseData.setToken(null);}return responseData;} }

    7)Postman查看情況

    ?

    轉載于:https://www.cnblogs.com/it-taosir/p/10021811.html

    總結

    以上是生活随笔為你收集整理的初识单点登录及JWT实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。