溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring Boot Security OAuth2 實(shí)現(xiàn)支持JWT令牌的授權(quán)服務(wù)器

發(fā)布時(shí)間:2020-07-22 07:59:11 來源:網(wǎng)絡(luò) 閱讀:910 作者:程序員果果 欄目:編程語言

概要

之前的兩篇文章,講述了Spring Security 結(jié)合 OAuth3 、JWT 的使用,這一節(jié)要求對 OAuth3、JWT 有了解,若不清楚,先移步到下面兩篇提前了解下。

Spring Boot Security 整合 OAuth3 設(shè)計(jì)安全API接口服務(wù)

Spring Boot Security 整合 JWT 實(shí)現(xiàn) 無狀態(tài)的分布式API接口

這一篇我們來實(shí)現(xiàn) 支持 JWT令牌 的授權(quán)服務(wù)器。

優(yōu)點(diǎn)

使用 OAuth3 是向認(rèn)證服務(wù)器申請令牌,客戶端拿這令牌訪問資源服務(wù)服務(wù)器,資源服務(wù)器校驗(yàn)了令牌無誤后,如果資源的訪問用到用戶的相關(guān)信息,那么資源服務(wù)器還需要根據(jù)令牌關(guān)聯(lián)查詢用戶的信息。

使用 JWT 是客戶端通過用戶名、密碼 請求服務(wù)器獲取 JWT,服務(wù)器判斷用戶名和密碼無誤之后,可以將用戶信息和權(quán)限信息經(jīng)過加密成 JWT 的形式返回給客戶端。在之后的請求中,客戶端攜帶 JWT 請求需要訪問的資源,如果資源的訪問用到用戶的相關(guān)信息,那么就直接從JWT中獲取到。

所以,如果我們在使用 OAuth3 時(shí)結(jié)合JWT ,就能節(jié)省集中式令牌校驗(yàn)開銷,實(shí)現(xiàn)無狀態(tài)授權(quán)認(rèn)證。

快速上手

項(xiàng)目說明

工程名 端口 作用
jwt-authserver 8080 授權(quán)服務(wù)器
jwt-resourceserver 8081 資源服務(wù)器

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

pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth3-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth3-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth3-autoconfigure</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-jwt</artifactId>
    <version>1.0.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
WebSecurityConfig
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
             authorizeRequests().antMatchers("/**").permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("user").password("123456").roles("USER");
    }

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return Objects.equals(charSequence.toString(),s);
            }
        };
    }

}

為了方便,使用內(nèi)存模式,在內(nèi)存中創(chuàng)建一個(gè)用戶 user 密碼 123456。

OAuth3AuthorizationServer
/**
 * 授權(quán)服務(wù)器
 */
@Configuration
@EnableAuthorizationServer
public class OAuth3AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    /**
     * 注入AuthenticationManager ,密碼模式用到
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 對Jwt簽名時(shí),增加一個(gè)密鑰
     * JwtAccessTokenConverter:對Jwt來進(jìn)行編碼以及解碼的類
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("test-secret");
        return converter;
    }

    /**
     * 設(shè)置token 由Jwt產(chǎn)生,不使用默認(rèn)的透明令牌
     */
    @Bean
    public JwtTokenStore jwtTokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .tokenStore(jwtTokenStore())
                .accessTokenConverter(accessTokenConverter());
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("clientapp")
                .secret("123")
                .scopes("read")
                //設(shè)置支持[密碼模式、授權(quán)碼模式、token刷新]
                .authorizedGrantTypes(
                        "password",
                        "authorization_code",
                        "refresh_token");
    }

}

資源服務(wù)器

pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth3-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth3-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth3-autoconfigure</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-jwt</artifactId>
    <version>1.0.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
HelloController
@RestController("/api")
public class HelloController {

    @PostMapping("/api/hi")
    public String say(String name) {
        return "hi , " + name;
    }

}
OAuth3ResourceServer
/**
 * 資源服務(wù)器
 */
@Configuration
@EnableResourceServer
public class OAuth3ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated().and()
            .requestMatchers().antMatchers("/api/**");
    }
}
application.yml
server:
  port: 8081

security:
  oauth3:
    resource:
      jwt:
        key-value: test-secret

參數(shù)說明:

  • security.oauth3.resource.jwt.key-value:設(shè)置簽名key 保持和授權(quán)服務(wù)器一致。
  • security.oauth3.resource.jwt:項(xiàng)目啟動(dòng)過程中,檢查到配置文件中有
    security.oauth3.resource.jwt 的配置,就會(huì)生成 jwtTokenStore 的 bean,對令牌的校驗(yàn)就會(huì)使用 jwtTokenStore 。

驗(yàn)證

請求令牌

curl -X POST --user 'clientapp:123' -d 'grant_type=password&username=user&password=123456' http://localhost:8080/oauth/token

返回JWT令牌

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ0MzExMDgsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGM0YWMyOTYtMDQwYS00Y2UzLTg5MTAtMWJmNjZkYTQwOTk3IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIiwic2NvcGUiOlsicmVhZCJdfQ.YAaSRN0iftmlR6Khz9UxNNEpHHn8zhZwlQrCUCPUmsU",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicmVhZCJdLCJhdGkiOiI4YzRhYzI5Ni0wNDBhLTRjZTMtODkxMC0xYmY2NmRhNDA5OTciLCJleHAiOjE1NTY5Nzk5MDgsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiI0ZjA5M2ZjYS04NmM0LTQxZWUtODcxZS1kZTY2ZjFhOTI0NTAiLCJjbGllbnRfaWQiOiJjbGllbnRhcHAifQ.vvAE2LcqggBv8pxuqU6RKPX65bl7Zl9dfcoIbIQBLf4",
    "expires_in": 43199,
    "scope": "read",
    "jti": "8c4ac296-040a-4ce3-8910-1bf66da40997"
}

攜帶JWT令牌請求資源

curl -X POST -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ0MzExMDgsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGM0YWMyOTYtMDQwYS00Y2UzLTg5MTAtMWJmNjZkYTQwOTk3IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIiwic2NvcGUiOlsicmVhZCJdfQ.YAaSRN0iftmlR6Khz9UxNNEpHHn8zhZwlQrCUCPUmsU" -d 'name=zhangsan' http://localhost:8081/api/hi

返回

hi , zhangsan

源碼

https://github.com/gf-huanchupk/SpringBootLearning/tree/master/springboot-security-oauth3-jwt

歡迎關(guān)注我的公眾號(hào)《程序員果果》,關(guān)注有驚喜~~
Spring Boot Security OAuth2 實(shí)現(xiàn)支持JWT令牌的授權(quán)服務(wù)器

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI