JWT單點登錄代碼實現(Demo詳解)

你好我是辰兮,很高興你能來閱讀,本篇給你介紹JWT單點登錄的代碼實現,後續會進一步分享源碼的學習,獻給初學者,共同成長,家一起進步。



一、SSO概念

單點登錄(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。

在這裏插入圖片描述
阿里系的淘寶和天貓,很明顯地我們可以知道這是兩個系統,但是你在使用的時候,登錄了天貓,淘寶也會自動登錄。

簡述:當你成功登錄後,系統會返回你一個令牌(憑證),你可以拿着這個令牌去訪問所有相關的系統,只要你令牌即可訪問,沒有令牌就被攔截不能訪問。(參考下圖)
在這裏插入圖片描述

1、相比於單系統登錄,sso需要一個獨立的認證中心,只有認證中心能接受用戶的用戶名密碼等安全信息,其他系統不提供登錄入口,只接受認證中心的間接授權。

2、間接授權通過令牌實現,sso認證中心驗證用戶的用戶名密碼沒問題,創建授權令牌,在接下來的跳轉過程中,授權令牌作爲參數發送給各個子系統,子系統拿到令牌,即得到了授權,可以藉此創建局部會話,局部會話登錄方式與單系統的登錄方式相同。


二、JWT單點登錄步驟

添加依賴

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.8.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

controller層的實現

    @RequestMapping("/login")
    public Map<String,String> login(String userName, String password){
        Map<String,String> map=new HashMap<>();
        try{
            String token = Jwts.builder().setSubject(userName) //主題,可以放用戶的詳細信息
                    .setIssuedAt(new Date()) //token創建時間
                    .setExpiration(new Date(System.currentTimeMillis() + 60000)) //token過期時間
                    .setId("userId") //用戶ID
                    //.setClaims(hashMap) //配置角色信息
                    .signWith(SignatureAlgorithm.HS256, "WuHan") //加密方式和加密密碼
                    .compact();
          //  System.out.println("token:"+token);
            map.put("code","1");
            map.put("msg","success");
            map.put("token",token);
            map.put("user",userName);
        }catch (Exception e){
            map.put("code","0");
            map.put("msg","fail");
            e.printStackTrace();
        }
        return map;
    }

登錄後可以把token打印出來自己看看,測試如下

token:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4YyIsImlhdCI6MTU5MTE1NDQwNiwiZXhwIjoxNTkxMTU0NDY2LCJqdGkiOiJ1c2VySWQifQ.c7gCDgIQ_I40dIWRxyG4yd1xaZQyWflnC7kX2Uoc9H8
token:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4YyIsImlhdCI6MTU5MTE1OTA1MSwiZXhwIjoxNTkxMTU5MTExLCJqdGkiOiJ1c2VySWQifQ.eUp0O2y83dc14f9NPUX049E9VxMpnkjuTcrheq2r9fM

token構成包含三個部分:

  • Header 頭部
  • Payload 負載
  • Signature 簽名
    在這裏插入圖片描述

注意事項:
①根據需求設計過期時間(1秒 =1000 毫秒 )
②因爲我把時間設計到token裏面了所以你可以測試每次產生的token不一樣
③設置userId那一欄-我目前是寫死了 setId(“userId”) ,你可以根據需求設計不同的值進去


校驗Token

try {
    JwtParser parser = Jwts.parser();
    parser.setSigningKey("WuHan");//解析 要和上面“暗號”一樣
    Jws<Claims> claimsJws = parser.parseClaimsJws(token);
    Claims body = claimsJws.getBody();
    String username = body.getSubject();
  //  Object role = body.get("role");

    return true;
} catch (ExpiredJwtException e) {
    e.printStackTrace();
} catch (UnsupportedJwtException e) {
    e.printStackTrace();
} catch (MalformedJwtException e) {
    e.printStackTrace();
} catch (SignatureException e) {
    e.printStackTrace();
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}

setSigningKey() 與builder中籤名方法signWith()對應,parser中的此方法擁有與signWith()方法相同的三種參數形式,用於設置JWT的簽名key,用戶後面對JWT進行解析。

isSigned() 校驗JWT是否進行簽名。方法很簡單,以分隔符" . ",截取JWT第三段,即簽名部分進行判斷。


  • 案例前端代碼實現登錄模塊如果成功登錄,則存放token(也可以存放user根據需求看)
 <script type="text/javascript">
     
            $("#login").click(function () {
                var name=$("#userName").val();
                var pwd=$("#password").val();
                $.post("http://localhost:8080/user/login",{userName:name,password:pwd},function(data) {
                    console.log(data);
                    if(data.code=="1"){
                      /*  document.cookie=data.token;*/
                        sessionStorage.setItem("token",data.token);
                        sessionStorage.setItem("user",data.user);
                        window.location.href="index.html";
                    }else{
                        window.location.href="login.html";
                    }
                },"json");
            });   
    </script>
  • 後續相關頁面的安全校驗,如果需要token才能訪問的頁面從存儲的地方取出token,來進行校驗,沒有token說明沒有登錄則返回登錄界面
    <script>
        var data = sessionStorage.getItem("token");
        if(data==null){
            window.location.href="login.html";
        }
    </script>
  • 補充:sessionStorage和localStorage
代碼 含義
window.sessionStorage(會話存儲) 暫時儲存,瀏覽器關閉之後會清除
window.localStorage (本地存儲) 本地儲存,瀏覽器關閉之後依舊不會清除,只能人爲刪除
  • 平時儲存的話建議使用sessionStorage;

開啓Springboot攔截器引用上述校驗token的代碼

/**
 * 登錄攔截
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getParameter("token");
        try {
            JwtParser parser = Jwts.parser();
            parser.setSigningKey("WuHan");
            Jws<Claims> claimsJws = parser.parseClaimsJws(token);
            Claims body = claimsJws.getBody();
            String username = body.getSubject();
            Object role = body.get("role");
            return true;
        } catch (ExpiredJwtException e) {
            e.printStackTrace();
        } catch (UnsupportedJwtException e) {
            e.printStackTrace();
        } catch (MalformedJwtException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

加載攔截器

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Resource
    private LoginInterceptor loginInterceptor;

    /**
     * 添加攔截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //.execudePathPatterns()//可以添加不攔截的地址
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
    }
}

The best investment is to invest in yourself

在這裏插入圖片描述

2020.06.03 記錄辰兮的第75篇博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章