真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JWT和Session的區(qū)別在哪里

本篇內(nèi)容主要講解“JWT和Session的區(qū)別在哪里”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“JWT和Session的區(qū)別在哪里”吧!

為梅列等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及梅列網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站建設(shè)、做網(wǎng)站、梅列網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

(一)前言

在前面一篇講分布式session的時(shí)候,有讀者問(wèn)了一句用JWT不香嗎,連redis服務(wù)器都省了,又可以實(shí)現(xiàn)分布式環(huán)境下的人員信息認(rèn)證。正好我也還沒(méi)寫(xiě)過(guò)關(guān)于JWT的文章,剛好在項(xiàng)目中又用過(guò)這項(xiàng)技術(shù),今天就來(lái)分享一下。還是一樣,先理論后實(shí)踐,有問(wèn)題評(píng)論一起頭腦風(fēng)暴。

(二)什么是JWT

JWT全程JSON Web Token,用戶會(huì)話信息存儲(chǔ)在客戶端瀏覽器中,各方之間通過(guò)JSON對(duì)象安全傳輸信息,這些信息可以通過(guò)加密算法進(jìn)行加密。

這樣描述可能比較難懂,簡(jiǎn)單來(lái)講,JWT就是在你登陸的時(shí)候生成一串加密字符串token,在每次請(qǐng)求的時(shí)候都帶上這串token,服務(wù)器如果可以解密這段字符串,說(shuō)明就是登陸狀態(tài)的。

我們一般會(huì)將非敏感數(shù)據(jù)加密生成token,如果服務(wù)器端需要用到人員信息,就解密取人員信息。

你會(huì)發(fā)現(xiàn),使用JWT直接就解決了分布式集群環(huán)境下的人員認(rèn)證問(wèn)題,因?yàn)樯傻倪@串token在哪臺(tái)服務(wù)器上都可以解析出來(lái)。如下圖所示:

JWT和Session的區(qū)別在哪里

了解了原理之后,來(lái)講講實(shí)際的,JWT的數(shù)據(jù)包含三個(gè)部分:

1、Header 2、Payload 3、Signature

三者通過(guò)"."組合在一起,經(jīng)過(guò)加密后生成一段token:

Header.Payload.Signature

下面是我生成的一段token

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqYXZheXoiLCJjcmVhdGVkYXRlIjoxNjExNzU1MDIxNjk1LCJpZCI6MSwiZXhwIjoxNjEyMzU5ODIxLCJ1c2VyTGV2ZWxJZCI6bnVsbH0.ahFWQ_BJ1WNWp9GnlTrSNThVa3i3dydzcaNxLmPb7HI

Header用來(lái)描述JWT元數(shù)據(jù),包含兩個(gè)數(shù)據(jù),其中alg表示簽名的算法,默認(rèn)HS256,typ屬性表示令牌類型,這里就是JWT。上面生成的token中第一個(gè)“.”之前的數(shù)據(jù)base64解碼后就是下面的json

{
    alg : "HS256",
    typ : "JWT"
}

Payload用來(lái)以JSON格式記錄用戶信息,這里的用戶信息可以自定義,上面第一個(gè)“.”和第二個(gè)“.”之間的數(shù)據(jù)base64解碼后就是下面的json

{
    "sub":"javayz",
    "createdate":1611755021695,
    "id":1,
    "exp":1612359821,
    "userLevelId":null
}

Signature存放加密串,通過(guò)指定算法對(duì)Header和Payload加鹽加密,各部分通過(guò)“.”分割。組成了token。

(三)JWT身份認(rèn)證流程

看完上面的內(nèi)容,我相信你對(duì)JWT的認(rèn)證已經(jīng)有認(rèn)識(shí)了,其身份認(rèn)證的流程如下所示:

1、用戶輸入用戶名和密碼登陸

2、服務(wù)器端校驗(yàn)用戶名和密碼是否正確,如果正確就返回token給客戶端

3、客戶端將token存放在cookie或者local storage中

4、客戶端后續(xù)的每次請(qǐng)求,都要帶上這個(gè)token

5、服務(wù)器通過(guò)token判斷是哪個(gè)用戶

(四)代碼實(shí)踐

接下通過(guò)代碼模擬JWT的認(rèn)證實(shí)現(xiàn),我寫(xiě)這段代碼時(shí)的環(huán)境為springBoot2.4.2,引入JWT依賴:



    io.jsonwebtoken
    jjwt
    0.9.0

在配置文件中配置一些接下來(lái)會(huì)用到的屬性:

jwt:
  tokenHeader: Authorization
  secret: javayz
  expiration: 604800
  tokenHead: Bearer

寫(xiě)個(gè)類來(lái)讀取這些參數(shù):

@Data
@ConfigurationProperties(prefix = "jwt")
@Component
public class JwtProperties {
    private String tokenHeader;
    private String secret;
    private Long expiration;
    private String tokenHead;
}

編寫(xiě)JWT工具類,實(shí)現(xiàn)生成token和解碼token的功能:

public class JwtKit {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 創(chuàng)建token
     * @param user
     * @return
     */
    public String generateJwtToken(User user){
        //所有的用戶數(shù)據(jù)放在claims中
        Map claims=new HashMap<>();
        claims.put("sub",user.getUsername());
        claims.put("createdate",new Date());
        claims.put("id",user.getId());
        claims.put("userLevelId",user.getLevelId());

        return Jwts.builder()
                .setClaims(claims)
                .setHeaderParam("typ", "JWT")
                .setExpiration(new Date(System.currentTimeMillis()+jwtProperties.getExpiration()*1000))
                .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecret())
                .compact();
    }

    /**
     * 解碼token
     * @param jwtToken
     * @return
     */
    public Claims parseJwtToken(String jwtToken){
        Claims claims=null;
        try {
            claims=Jwts.parser()
                    .setSigningKey(jwtProperties.getSecret())
                    .parseClaimsJws(jwtToken)
                    .getBody();
        }catch (ExpiredJwtException e){
            throw new MyException("JWTtoken過(guò)期");
        }catch (UnsupportedJwtException e){
            throw new MyException("JWTtoken格式不支持");
        }catch (MalformedJwtException e){
            throw new MyException("無(wú)效的token");
        }catch (SignatureException e){
            throw new MyException("無(wú)效的token");
        }catch (IllegalArgumentException e){
            throw new MyException("無(wú)效的token");
        }
        return claims;
    }
}

再將這個(gè)工具類注入到Bean容器中:

@Configuration
public class JwtConfiguration {

    @Bean
    public JwtKit jwtKit(){
        return new JwtKit();
    }
}

然后就可以愉快地使用了

@RestController
@RequestMapping("/sso")
public class UserController extends BaseController {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtKit jwtKit;

    @Autowired
    private JwtProperties jwtProperties;

    @PostMapping("jwtlogin")
    public CommonResult jwtLogin(@RequestParam String username,@RequestParam String password){
        User user = userService.login(username, password);
        if (user!=null){
            Map map=new HashMap<>();
            String token=jwtKit.generateJwtToken(user);
            map.put("tokenHead",jwtProperties.getTokenHead());
            map.put("token",token);
            return new CommonResult(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),map);
        }
        return new CommonResult(ResponseCode.USER_NOT_EXISTS.getCode(),ResponseCode.USER_NOT_EXISTS.getMsg(),"");
    }
}

登陸成功的話將token的開(kāi)頭和實(shí)際token值返回給后端。

接著編寫(xiě)攔截器,攔截除/sso/*外的其他請(qǐng)求,這些請(qǐng)求是需要登陸才可以訪問(wèn)的。

@Configuration
public class IntercepterConfiguration implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List list=new ArrayList();
        list.add("/sso/**");
        registry.addInterceptor(authInterceptorHandler())
                .addPathPatterns("/**")
                .excludePathPatterns(list);
    }

    @Bean
    public AuthInterceptorHandler authInterceptorHandler(){
        return new AuthInterceptorHandler();
    }
}

接著是對(duì)攔截的處理,首先判斷header中是否有key為Authorization的數(shù)據(jù),如果沒(méi)有,說(shuō)明未登陸,將未登錄的結(jié)果返回出去。如果header中存在key為Authorization的數(shù)據(jù),則先判斷是否以Bearer開(kāi)頭(這個(gè)可以自定義),如果是的話說(shuō)明登陸了,就直接返回true不攔截。

@Slf4j
public class AuthInterceptorHandler implements HandlerInterceptor {

    @Autowired
    private JwtKit jwtKit;

    @Autowired
    private JwtProperties jwtProperties;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("進(jìn)入攔截器");
        String aa = request.getHeader("aa");
        String authorization =request.getHeader(jwtProperties.getTokenHeader());
        log.info("Authorization"+authorization);
        //如果不為空,說(shuō)明head里存了數(shù)據(jù),
        if(StringUtils.isNotEmpty(authorization) && authorization.startsWith(jwtProperties.getTokenHead())){
            String authToken = authorization.substring(jwtProperties.getTokenHead().length());
            Claims claims=null;
            try {
                claims=jwtKit.parseJwtToken(authToken);
                if (claims!=null){
                    return true;
                }
            }catch (MyException e){
                log.info(e.getMessage()+":"+authToken);
            }
        }

        response.setHeader("Content-Type","application/json");
        response.setCharacterEncoding("UTF-8");
        String result = new ObjectMapper().writeValueAsString(new CommonResult(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getMsg(), ""));
        response.getWriter().println(result);
        return false;
    }
}

最后寫(xiě)一個(gè)測(cè)試類:

@RestController
public class IndexController extends BaseController{

    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private JwtKit jwtKit;

    @RequestMapping(value = "/index",method = RequestMethod.GET)
    public CommonResult index(){

        String authorization = getRequest().getHeader(jwtProperties.getTokenHeader());
        String authToken = authorization.substring(jwtProperties.getTokenHead().length());
        Claims claims=jwtKit.parseJwtToken(authToken);
        return new CommonResult(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),claims.get("sub"));
    }
}

(五)效果測(cè)試

首先我直接訪問(wèn)http://localhost:8189/index,返回結(jié)果為登陸失效,因?yàn)闆](méi)有傳header

JWT和Session的區(qū)別在哪里

于是先訪問(wèn)登陸接口:http://localhost:8189/sso/jwtlogin

JWT和Session的區(qū)別在哪里

返回了具體的tokenHead和token實(shí)際值。 將這個(gè)token放進(jìn)header里,再次訪問(wèn)index接口:

JWT和Session的區(qū)別在哪里

操作成功,并且可以取到用戶信息。

(六)JWT和Session的對(duì)比

前面一篇文章我用了Session實(shí)現(xiàn)了認(rèn)證的功能,但是需要額外的Redis服務(wù)器才可以實(shí)現(xiàn)分布式的認(rèn)證。而使用JWT不需要額外的服務(wù)器,它是把token放在header中的。

但是JWT同樣存在缺點(diǎn),最明顯的就是這段token無(wú)法讓他手動(dòng)失效,生成token后,就算注銷登陸,token依然是有效的。

第二點(diǎn)缺點(diǎn)是人員信息是base64后的數(shù)據(jù),相當(dāng)于只要拿到就可以被使用,因此JWT只能傳輸非敏感的人員數(shù)據(jù)。

第三點(diǎn)缺點(diǎn)是由于每次請(qǐng)求都需要在header中攜帶token信息,增大了帶寬的壓力。別覺(jué)得一個(gè)請(qǐng)求的header就多占用了那么一點(diǎn)帶寬,如果是一萬(wàn)個(gè)或者是十萬(wàn)個(gè)請(qǐng)求呢?帶寬的資源是很珍貴的。

到此,相信大家對(duì)“JWT和Session的區(qū)別在哪里”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


名稱欄目:JWT和Session的區(qū)別在哪里
標(biāo)題來(lái)源:http://weahome.cn/article/ihchhs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部