亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于SpringBoot創(chuàng)建存儲(chǔ)令牌的媒介類和過(guò)濾器的問(wèn)題

 更新時(shí)間:2021年09月15日 15:16:27   作者:曉夢(mèng)林  
這篇文章主要介紹了SpringBoot創(chuàng)建存儲(chǔ)令牌的媒介類和過(guò)濾器的問(wèn)題,需要在配置文件中,添加JWT需要的密匙,過(guò)期時(shí)間和緩存過(guò)期時(shí)間,具體實(shí)例代碼參考下本文

之所以需要?jiǎng)?chuàng)建存儲(chǔ)令牌的媒介類,是因?yàn)楹竺娴膄ilter界面要使用。

一、創(chuàng)建ThreadLocalToken類

創(chuàng)建ThreadLocalToken類的目的:

在這里插入圖片描述

com.example.emos.wx.config.shiro中創(chuàng)建ThreadLocalToken類。
寫入如下代碼:

package com.example.emos.wx.config.shiro;

import org.springframework.stereotype.Component;

@Component
public class ThreadLocalToken {
    private ThreadLocal local=new ThreadLocal();

    //因?yàn)橐赥hreadLocal中保存令牌,所以需要setToken。
    public void setToken(String token){
        local.set(token);
    }

    public String getToken(){
        return (String) local.get();
    }

    public void clear(){
        local.remove();//把綁定的數(shù)據(jù)刪除了
    }
}

下圖為創(chuàng)建目錄的層級(jí)關(guān)系:

在這里插入圖片描述

二、創(chuàng)建OAuth2Filter類

創(chuàng)建過(guò)濾器的目的:

在這里插入圖片描述

因?yàn)?code>OAuth2Filter類要讀寫ThreadLocal中的數(shù)據(jù),所以OAuth2Filter類必須要設(shè)置成多例的,否則ThreadLocal將無(wú)法使用。
在配置文件中,添加JWT需要的密匙,過(guò)期時(shí)間和緩存過(guò)期時(shí)間。

emos:
  jwt:
    #密鑰
    secret: abc123456
    #令牌過(guò)期時(shí)間(天)
    expire:  5
    #令牌緩存時(shí)間(天數(shù))
    cache-expire: 10

com.example.emos.wx.config.shiro中創(chuàng)建OAuth2Filter類。

package com.example.emos.wx.config.shiro;

import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

在寫好@Scope("prototype")后,就表明以后Spring使用OAuth2Filter類默認(rèn)是多例。

@Value("${emos.jwt.cache-expire}")
考察的一個(gè)知識(shí)點(diǎn),從xml文件中獲取屬性文件的屬性值。

因?yàn)橐赗edis中操作,所以要聲明private RedisTemplate redisTemplate;
申明好這個(gè)對(duì)象后,就可以對(duì)redis中的數(shù)據(jù)進(jìn)行讀寫操作了。

filter類用來(lái)區(qū)分哪些請(qǐng)求應(yīng)該被shiro處理,哪些請(qǐng)求不該被shiro處理。
如果請(qǐng)求被shiro處理的話,那么createToken方法就被執(zhí)行了,
createToken從請(qǐng)求中獲取令牌字符串,然后封裝成令牌對(duì)象OAuth2Token,交給shiro框架去處理。

getRequestToken是一個(gè)自定義方法,用來(lái)獲取令牌字符串,然后傳遞給字符串Token對(duì)象。

@Component
@Scope("prototype")
public class OAuth2Filter extends AuthenticatingFilter {
    @Autowired
    private ThreadLocalToken threadLocalToken;

    @Value("${emos.jwt.cache-expire}")
    private int cacheExpire;

    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
	 * 攔截請(qǐng)求之后,用于把令牌字符串封裝成令牌對(duì)象
	 */
	@Override
    protected AuthenticationToken createToken(ServletRequest request, 
		ServletResponse response) throws Exception {
        //獲取請(qǐng)求token
        String token = getRequestToken((HttpServletRequest) request);

        if (StringUtils.isBlank(token)) {
            return null;
        }

        return new OAuth2Token(token);
    }

filter過(guò)濾這一塊細(xì)講一下:
isAccessAllowed是判斷哪些請(qǐng)求可以被shiro處理,哪些不可以被shiro處理。
由于isAccessAllowed方法中requestServletRequest ,所以需要進(jìn)行轉(zhuǎn)換HttpServletRequest,
然后判斷這次request請(qǐng)求是不是options請(qǐng)求。如果不是,就需要被shiro處理。

 /**
	 * 攔截請(qǐng)求,判斷請(qǐng)求是否需要被Shiro處理
	 */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, 
		ServletResponse response, Object mappedValue) {
        HttpServletRequest req = (HttpServletRequest) request;
        // Ajax提交application/json數(shù)據(jù)的時(shí)候,會(huì)先發(fā)出Options請(qǐng)求
		// 這里要放行Options請(qǐng)求,不需要Shiro處理
		if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
            return true;
        }
		// 除了Options請(qǐng)求之外,所有請(qǐng)求都要被Shiro處理
        return false;
    }

那么,shiro是怎么處理的呢?

onAccessDenied 方法

設(shè)置響應(yīng)的字符集,和響應(yīng)的請(qǐng)求頭。setHeader方法用來(lái)設(shè)置跨域請(qǐng)求。

/**
	 * 該方法用于處理所有應(yīng)該被Shiro處理的請(qǐng)求
	 */
    @Override
    protected boolean onAccessDenied(ServletRequest request, 
		ServletResponse response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

		resp.setHeader("Content-Type", "text/html;charset=UTF-8");
		//允許跨域請(qǐng)求
        resp.setHeader("Access-Control-Allow-Credentials", "true");
        resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
        
		//clear方法用來(lái)清理threadLocal類中的方法,
		threadLocalToken.clear();
		
        //獲取請(qǐng)求token,如果token不存在,直接返回401
        String token = getRequestToken((HttpServletRequest) request);
        if (StringUtils.isBlank(token)) {
            resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
            resp.getWriter().print("無(wú)效的令牌");
            return false;
        }

然后驗(yàn)證令牌是否過(guò)期。
如果驗(yàn)證出現(xiàn)問(wèn)題,就會(huì)拋出異常。
通過(guò)捕獲異常,就知道是令牌有問(wèn)題,還是令牌過(guò)期了。
JWTDecodeException 是內(nèi)容異常。

通過(guò)redisTemplatehasKey查詢Redis是否存在令牌。
如果存在令牌,就刪除老令牌,重新生成一個(gè)令牌,給客戶端。
executeLogin方法,讓shiro執(zhí)行realm類。

 try {
            jwtUtil.verifierToken(token); //檢查令牌是否過(guò)期
        } catch (TokenExpiredException e) {
            //客戶端令牌過(guò)期,查詢Redis中是否存在令牌,如果存在令牌就重新生成一個(gè)令牌給客戶端
            if (redisTemplate.hasKey(token)) {
                redisTemplate.delete(token);//刪除老令牌
                int userId = jwtUtil.getUserId(token);
                token = jwtUtil.createToken(userId);  //生成新的令牌
                //把新的令牌保存到Redis中
                redisTemplate.opsForValue().set(token, userId + "", cacheExpire, TimeUnit.DAYS);
                //把新令牌綁定到線程
                threadLocalToken.setToken(token);
            } else {
                //如果Redis不存在令牌,讓用戶重新登錄
                resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
                resp.getWriter().print("令牌已經(jīng)過(guò)期");
                return false;
            }

        } catch (JWTDecodeException e) {
            resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
            resp.getWriter().print("無(wú)效的令牌");
            return false;
        }

        boolean bool = executeLogin(request, response);
        return bool;
    }

登錄失敗后輸出的信息。

 @Override
    protected boolean onLoginFailure(AuthenticationToken token,
		AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
        resp.setContentType("application/json;charset=utf-8");
        resp.setHeader("Access-Control-Allow-Credentials", "true");
        resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
        try {
            resp.getWriter().print(e.getMessage());//捕獲認(rèn)證失敗的消息
        } catch (IOException exception) {

        }
        return false;
    }

獲取請(qǐng)求頭里面的token

 /**
     * 獲取請(qǐng)求頭里面的token
     */
    private String getRequestToken(HttpServletRequest httpRequest) {
        //從header中獲取token
        String token = httpRequest.getHeader("token");

        //如果header中不存在token,則從參數(shù)中獲取token
        if (StringUtils.isBlank(token)) {
            token = httpRequest.getParameter("token");
        }
        return token;

    }

doFilterInternal方法從父類doFilterInternal中繼承,掌管攔截請(qǐng)求和響應(yīng)的。這里不覆寫。

 @Override
    public void doFilterInternal(ServletRequest request, 
		ServletResponse response, FilterChain chain) throws ServletException, IOException {
        super.doFilterInternal(request, response, chain);
    }
}

到此這篇關(guān)于SpringBoot創(chuàng)建存儲(chǔ)令牌的媒介類和過(guò)濾器的文章就介紹到這了,更多相關(guān)SpringBoot內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Datagram Scoket雙向通信

    Datagram Scoket雙向通信

    這篇文章主要介紹了Datagram Scoket雙向通信,需要的朋友可以參考下
    2014-04-04
  • MyBatisPlus3.x中使用代碼生成器(全注釋)

    MyBatisPlus3.x中使用代碼生成器(全注釋)

    這篇文章主要介紹了MyBatisPlus3.x中使用代碼生成器(全注釋),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java項(xiàng)目啟動(dòng)失敗的問(wèn)題及解決

    java項(xiàng)目啟動(dòng)失敗的問(wèn)題及解決

    這篇文章主要介紹了java項(xiàng)目啟動(dòng)失敗的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • redis實(shí)現(xiàn)隊(duì)列的阻塞、延時(shí)、發(fā)布和訂閱

    redis實(shí)現(xiàn)隊(duì)列的阻塞、延時(shí)、發(fā)布和訂閱

    本文主要介紹了redis實(shí)現(xiàn)隊(duì)列的阻塞、延時(shí)、發(fā)布和訂閱,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Java接口自動(dòng)化測(cè)試框架設(shè)計(jì)之Get請(qǐng)求方法和測(cè)試詳解

    Java接口自動(dòng)化測(cè)試框架設(shè)計(jì)之Get請(qǐng)求方法和測(cè)試詳解

    這篇文章主要介紹了Java接口自動(dòng)化測(cè)試框架設(shè)計(jì) Get請(qǐng)求方法和測(cè)試,框架設(shè)計(jì)我們只是介紹基本的組件,而且框架設(shè)計(jì)沒有想象那么難,一步一步跟著做就會(huì)了。這篇我們來(lái)演示,如果通過(guò)Java代碼來(lái)實(shí)現(xiàn)一個(gè)用純代碼實(shí)現(xiàn)Http中的Get請(qǐng)求過(guò)程,需要的朋友可以參考下
    2019-07-07
  • SpringBoot讀寫xml上傳到AWS存儲(chǔ)服務(wù)S3的示例

    SpringBoot讀寫xml上傳到AWS存儲(chǔ)服務(wù)S3的示例

    這篇文章主要介紹了SpringBoot讀寫xml上傳到S3的示例,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下
    2020-10-10
  • 16進(jìn)制顯示字節(jié)流技巧分享

    16進(jìn)制顯示字節(jié)流技巧分享

    這篇文章主要介紹了16進(jìn)制顯示字節(jié)流的技巧分享,需要的朋友可以參考下
    2014-02-02
  • Java下載項(xiàng)目中靜態(tài)文件方式

    Java下載項(xiàng)目中靜態(tài)文件方式

    這篇文章主要介紹了Java下載項(xiàng)目中靜態(tài)文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Java常用工具類—集合排序

    Java常用工具類—集合排序

    這篇文章主要介紹了Java集合排序,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java實(shí)現(xiàn)重定向過(guò)程中添加請(qǐng)求頭信息

    Java實(shí)現(xiàn)重定向過(guò)程中添加請(qǐng)求頭信息

    在Java中,我們經(jīng)常需要使用網(wǎng)絡(luò)請(qǐng)求來(lái)與服務(wù)器進(jìn)行通信,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),有時(shí)我們需要在重定向過(guò)程中添加請(qǐng)求頭信息,本文將介紹如何使用Java在重定向過(guò)程中添加請(qǐng)求頭,并提供相應(yīng)的代碼示例,
    2023-10-10

最新評(píng)論