最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用JWT作為Spring?Security?OAuth2的token存儲(chǔ)問(wèn)題

 更新時(shí)間:2021年12月24日 10:51:12   作者:東北小狐貍  
這篇文章主要介紹了使用JWT作為Spring?Security?OAuth2的token存儲(chǔ),大家經(jīng)常使用的方法有兩種一種是使用JWT作為Token傳遞,一種是使用Redis存儲(chǔ)Token,資源服務(wù)器本地訪問(wèn)Redis校驗(yàn)Token,需要的朋友可以參考下

Spring Security OAuth2的demo在前幾篇文章中已經(jīng)講過(guò)了,在那些模式中使用的都是RemoteTokenService調(diào)用授權(quán)服務(wù)器來(lái)校驗(yàn)token,返回校驗(yàn)通過(guò)的用戶信息供上下文中獲取

這種方式會(huì)加重授權(quán)服務(wù)器的負(fù)載,你想啊,當(dāng)用戶沒授權(quán)時(shí)候獲取token得找授權(quán)服務(wù)器,有token了訪問(wèn)資源服務(wù)器還要訪問(wèn)授權(quán)服務(wù)器,相當(dāng)于說(shuō)每次請(qǐng)求都要訪問(wèn)授權(quán)服務(wù)器,這樣對(duì)授權(quán)服務(wù)器的負(fù)載會(huì)很大

常規(guī)的方式有兩種來(lái)解決這個(gè)問(wèn)題:

  • 使用JWT作為Token傳遞
  • 使用Redis存儲(chǔ)Token,資源服務(wù)器本地訪問(wèn)Redis校驗(yàn)Token

使用JWT與Redis都可以在資源服務(wù)器中進(jìn)行校驗(yàn)Token,從而減少授權(quán)服務(wù)器的工作量

JWT默認(rèn)使用HMACSHA256對(duì)稱加密算法,以下記錄下默認(rèn)算法實(shí)現(xiàn)與非對(duì)稱RSA算法的集成,使用不同算法加解密測(cè)試方法是一致的,所以放在文章最后

授權(quán)服務(wù)器整合JWT——對(duì)稱加解密算法

授權(quán)服務(wù)器整體代碼結(jié)構(gòu)

pom.xml中引入依賴

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>        
		<!-- Spring Security OAuth2 -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.4.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>

SecurityConfig配置,主要需要顯式聲明AuthenticationManager和UserDetailsService這兩個(gè)bean

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    public UserDetailsService userDetailsService(){ //主要是配置這個(gè)Bean,用于授權(quán)服務(wù)器配置中注入
        return super.userDetailsService();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // @formatter: off
        auth.inMemoryAuthentication()
                .withUser("hellxz")
                .password(passwordEncoder().encode("xyz"))
                .authorities(Collections.emptyList());
        // @formatter: on
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated() //所有請(qǐng)求都需要通過(guò)認(rèn)證
                .and()
                .httpBasic() //Basic提交
                .and()
                .csrf().disable(); //關(guān)跨域保護(hù)
    }
}

授權(quán)服務(wù)器配置AuthorizationConfig

@Configuration
@EnableAuthorizationServer //開啟授權(quán)服務(wù)
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    public UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //允許表單提交
        security.allowFormAuthenticationForClients()
                .checkTokenAccess("permitAll()")
                .tokenKeyAccess("permitAll()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // @formatter: off
        clients.inMemory()
                .withClient("client-a") //client端唯一標(biāo)識(shí)
                    .secret(passwordEncoder.encode("client-a-secret")) //client-a的密碼,這里的密碼應(yīng)該是加密后的
                    .authorizedGrantTypes("authorization_code", "password", "refresh_token") //授權(quán)模式標(biāo)識(shí),這里主要測(cè)試用password模式,另外refresh_token不是一種模式,但是可以使用它來(lái)刷新access_token(在它的有效期內(nèi))
                    .scopes("read_user_info") //作用域
                    .resourceIds("resource1") //資源id,如不需限制資源id,注釋此處即可
                    .redirectUris("http://localhost:9001/callback"); //回調(diào)地址

        // @formatter: on
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .tokenStore(jwtTokenStore()) //設(shè)置jwtToken為tokenStore
                .accessTokenConverter(jwtAccessTokenConverter());//設(shè)置access_token轉(zhuǎn)換器
    }

    /**
     * jwt訪問(wèn)token轉(zhuǎn)換器
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("my-sign-key"); //資源服務(wù)器需要配置此選項(xiàng)方能解密jwt的token
        return converter;
    }

    /**
     * jwt的token存儲(chǔ)對(duì)象
     */
    @Bean
    public JwtTokenStore jwtTokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }
}

這里主要是在configure(AuthorizationServerEndpointsConfigurer endpoints)授權(quán)服務(wù)的端點(diǎn)配置中加入JWT的tokenStore和access_token的轉(zhuǎn)換器,以及這二者的聲明Bean方法

這里使用的是默認(rèn)對(duì)稱MAC算法,即加密解密使用相同的密鑰

啟動(dòng)類就不說(shuō)了,開啟@SpringBootApplicatin的main方法

資源服務(wù)器整合JWT——對(duì)稱加解密算法

資源服務(wù)器主要就一個(gè)資源配置類

@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        //設(shè)置創(chuàng)建session策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        //@formatter:off
        //所有請(qǐng)求必須授權(quán)
        http.authorizeRequests()
                .anyRequest().authenticated();
        //@formatter:on
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
    	//@formatter:off
    	//如不需要限制資源id,請(qǐng)?jiān)谑跈?quán)配置處去除resourceIds的配置
    	resources.resourceId("resource1")
        		 .tokenStore(jwtTokenStore());
    	//@formatter:on
    }

    /**
     * jwt訪問(wèn)token轉(zhuǎn)換器
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("my-sign-key"); //與授權(quán)服務(wù)器相同的signingKey
        return converter;
    }

    /**
     * jwt的token存儲(chǔ)對(duì)象
     */
    @Bean
    public JwtTokenStore jwtTokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }
}

配置JWT的TokenStore和AccessTokenConverter與授權(quán)服器相同,添加啟動(dòng)類完成配置

OAuth整合JWT——非對(duì)稱加解密RSA

本部分基于對(duì)稱加密部分,僅展示需要修改的部分

首先使用keytool生成jks (Java Key Store) 密鑰,按提示輸入姓氏等信息

keytool -genkeypair -alias hellxz-jwt -validity 3650 -keyalg RSA -keypass hellxzTest -keystore hellxz-jwt.jks -storepass hellxzTest

生成的私鑰文件會(huì)在當(dāng)前目錄,把hellxz-jwt.jks復(fù)制到授權(quán)服務(wù)器的resources目錄下
授權(quán)服務(wù)器需修改jwtAccessTokenConverter()

 @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        KeyStoreKeyFactory storeKeyFactory = new KeyStoreKeyFactory(
                new ClassPathResource("hellxz-jwt.jks"), "hellxzTest".toCharArray());
        converter.setKeyPair(storeKeyFactory.getKeyPair("hellxz-jwt"));
        return converter;
    }

在hellxz-jwt.jks同目錄下,執(zhí)行命令生成公鑰

? keytool -list -rfc --keystore hellxz-jwt.jks | openssl x509 -inform pem -pubkey

輸入密鑰庫(kù)口令:? hellxzTest

-----BEGIN PUBLIC KEY-----

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4

ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI

7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGgce9tR0Q0iONcaN+b/lArK4T

Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzqt6fEPWqalBUVYdV0zCUDG8ikN1

l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+

0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh

zQIDAQAB

-----END PUBLIC KEY-----

-----BEGIN CERTIFICATE-----

MIIDUTCCAjmgAwIBAgIEePeDczANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJD

TjEQMA4GA1UECBMHYmVpamluZzEQMA4GA1UEBxMHYmVpamluZzEKMAgGA1UEChMB

MDEKMAgGA1UECxMBMDEOMAwGA1UEAxMFemhhbmcwHhcNMTkxMjE1MDUyOTM2WhcN

MjkxMjEyMDUyOTM2WjBZMQswCQYDVQQGEwJDTjEQMA4GA1UECBMHYmVpamluZzEQ

MA4GA1UEBxMHYmVpamluZzEKMAgGA1UEChMBMDEKMAgGA1UECxMBMDEOMAwGA1UE

AxMFemhhbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFTvO6UVRU

FeZkPbzHAzi6Xl73IWtOguBYoeU0uWn3Tj8ZuJYGhni1wFw2rdXEsYE31U6p8/U/

kLt9GDP3lQjtKEoIqCwUUYvasCqymUwMKU39p1+zGakXTqtUiQaBx721HRDSI41x

o35v+UCsrhMC7vpCxDCf0wteXOdV9zNyVk5lJ8M2O77Um4HOq3p8Q9apqUFRVh1X

TMJQMbyKQ3WX0PSbW1JJoqmJOtTbIRQZSOL7v1SvLtjwEKURfp3gJOX1NACEvmDf

YagkRzRLbL7Rup6pSy/WdS30qIlP2SI68D5DujZPw4e6pBP2V7uS+YiLiBJfm9I2

+9lqATZSCWHNAgMBAAGjITAfMB0GA1UdDgQWBBQF96rK7n0XufnvtJuH9tD9Ixza

6zANBgkqhkiG9w0BAQsFAAOCAQEAuMzWZJhej6+4TGgodQKQ5L5RBtOUbesxA1Ue

s9iA4m/jNZnVCXJE0nY47YVzBCIkIsYALswGooMj1PIJxEMpggXVmIuiJpaPgg+4

sthzISxKzX0ru8IrJTapaglMi74ai6S73LTBSke9GEPgWWnbtdUZoUSiSNt1oJ0J

EhFHdPuzxc36neDFRBOBxW4w3qhsTlKTN2wJm1nLV96nFKmqJhQJhhKt6ihe7hMg

qWxzNsWAqv9gJNdKZt5teqwNKT6H7r1NX5oJkJ0Kn1dZy0O3rDDd5E0KDKkMtwOh

3deJH6Uvtt/dw/drzJlByNDEPp6hYGQu2dW5JG5uiHuzFHnJeA==

-----END CERTIFICATE-----

復(fù)制公鑰部分到public.cert放到資源服務(wù)器的resources目錄

-----BEGIN PUBLIC KEY-----

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4

ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI

7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGgce9tR0Q0iONcaN+b/lArK4T

Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzqt6fEPWqalBUVYdV0zCUDG8ikN1

l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+

0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh

zQIDAQAB

-----END PUBLIC KEY-----

修改資源服務(wù)器jwtAccessTokenConverter()方法

  @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("public.cert");
        String publicKey;
        try {
            publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        converter.setVerifierKey(publicKey);
        return converter;
    }

測(cè)試驗(yàn)證

發(fā)送POST請(qǐng)求http://localhost:8080/oauth/token?username=hellxz&password=xyz&scope=read_user_info&grant_type=password

返回結(jié)果

帶token訪問(wèn)資源服務(wù)器

測(cè)試通過(guò)

另外使用JWT應(yīng)設(shè)置盡量短的過(guò)期時(shí)間,因?yàn)镴WT的token無(wú)法手動(dòng)revoke,只能等待其到達(dá)過(guò)期時(shí)間失效

到此這篇關(guān)于使用JWT作為Spring Security OAuth2的token存儲(chǔ)的文章就介紹到這了,更多相關(guān)Spring Security OAuth2 token存儲(chǔ)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

寿光市| 桃江县| 丰县| 崇信县| 佛冈县| 福贡县| 高碑店市| 潍坊市| 秭归县| 南安市| 乐业县| 内乡县| 邳州市| 库尔勒市| 寿阳县| 曲麻莱县| 岑溪市| 瑞安市| 宣武区| 凌云县| 南皮县| 汶川县| 磐石市| 峨眉山市| 珲春市| 安新县| 新田县| 资讯 | 苏尼特右旗| 永春县| 古浪县| 社旗县| 博湖县| 射阳县| 洛浦县| 盘锦市| 万载县| 蛟河市| 界首市| 扎囊县| 石楼县|