OAuth2.0 使用 JWT令牌

应用背景:当资源服务和认证服务不在一起时,资源服务使用RemoteTokenServices远程请求授权服务验证token,如果访问量较大较会影响系统的性能。这时可以考虑做进一步的优化,令牌采用JWT格式生成,用户认证通过会得到一个JWT令牌,客户端只需要携带JWT令牌访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。

OAth2.0使用JWT令牌时,不再需要额外的依赖包,仅仅引入Spring Cloud整合OAuth2.0的依赖包即可,这是因为随着技术的发展,使用OAuth2.0的时候,其项目架构必然是分布式。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

认证服务器 需要做下述配置:

第一步:认证服务中原先产生Token的配置类为:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

@Configuration
public class TokenConfig {

    //认证服务器产生的Token采用内存进行存储
    @Bean
    public TokenStore tokenStore() {
        //内存方式,生成普通令牌
        return new InMemoryTokenStore();
    }
}

现在认证服务使用JWT方式产生令牌,因此此配置类需要修改为如下所示:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

@Configuration
public class TokenConfig {

    //认证服务器产生的Token采用JWT进行存储
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        //设置加密的密钥为“key123”,这是一个对称秘钥,资源服务器必须使用该秘钥来验证
        converter.setSigningKey("key123");
        return converter;
    }
}

第二步:资源服务的OAuth2的配置类(AuthorizationServerConfigurerAdapter的继承类)修改如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.Arrays;

/**
 * 授权服务配置
 **/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;
    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;
    @Autowired
    PasswordEncoder passwordEncoder;


    /**
     * 1.配置客户端详细信息服务
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //统一认证中心:使用内存方式存储客户端详细信息
       clients.inMemory()
                .withClient("c1")// client_id
                .secret(new BCryptPasswordEncoder().encode("secret"))//客户端密钥
                .resourceIds("res1")//资源列表
                .authorizedGrantTypes("authorization_code", "password","client_credentials","implicit","refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
                .scopes("all")// 允许的授权范围
                .autoApprove(false)//false跳转到授权页面
                //加上验证回调地址
                .redirectUris("http://www.baidu.com");
    }

    //2.令牌管理服务
    @Bean
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices service=new DefaultTokenServices();
        service.setClientDetailsService(clientDetailsService);//客户端信息服务
        service.setSupportRefreshToken(true);//支持刷新令牌
        service.setTokenStore(tokenStore);//令牌存储策略

        //使用JWT方式时,则开启下面三行代码,令牌增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
        service.setTokenEnhancer(tokenEnhancerChain);

        service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
        service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
        return service;
    }



    /**
     * 令牌访问端点
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .authenticationManager(authenticationManager)            //认证管理器
                .authorizationCodeServices(authorizationCodeServices)    //授权码服务
                .tokenServices(tokenService())//令牌管理服务
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }

    /**
     * 令牌端点的安全约束
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security){
        //允许所有的都可以访问oauth/token_key
        security.tokenKeyAccess("permitAll()")
                //允许所有的都可以访问oauth/check_token
                .checkTokenAccess("permitAll()")
                //表单认证(申请令牌)
                .allowFormAuthenticationForClients();
    }
}

特别提醒:使用JWT方式生成令牌,认证服务和资源服务的签名密钥必须要一致

资源服务器 需要做下述配置:

第一步:资源服务中添加验证JWT Token令牌的配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

/**
 * 资源服务验证JWT Token令牌的配置
 */
@Configuration
public class CheckJwtTokenConfig {

    //签名密钥与认证服务保持一致
    private String SigningKey="key123";

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SigningKey);
        return converter;
    }
}

第二步:在资源服务的配置类(ResourceServerConfigurerAdapter 的继承类)中将上述配置(tokenStore)应用,示例代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableResourceServer
public class ResouceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        //资源 id
        resources.resourceId("res1")
                //资源服务器使用本地认证方式验证JWT令牌
                .tokenStore(tokenStore)
                //验证令牌的服务,目前将下述这段token验证服务屏蔽掉
                //.tokenServices(tokenService())
                .stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**").access("#oauth2.hasScope('all')")
                .and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    /**
     * 功能描述:配置资源服务的令牌检查服务,如果使用的是JWT令牌,那么下面这段代码可以屏蔽掉
     */
    @Bean
    public ResourceServerTokenServices tokenService() {
        //创建“远程服务请求授权服务器”对象用于校验token
        RemoteTokenServices remoteTokenServices=new RemoteTokenServices();
        //1.指定校验Token的认证服务器(统一认证中心)的URL
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:53020/uaa/oauth/check_token");
        //2.配置当前资源服务的client_id
        remoteTokenServices.setClientId("c1");
        //3.配置当前资源服务的client_secret
        remoteTokenServices.setClientSecret("secret");
        return remoteTokenServices;
    }
}

 最后进行测试,先访问下述地址获取授权码

http://127.0.0.1:53020/uaa/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com

获取到了授权码Code以后,调用下述接口获取令牌:

http://127.0.0.1:53020/uaa/oauth/token?code=1e8pTX&grant_type=authorization_code&client_id=c1&client_secret=secret&redirect_uri=http://www.baidu.com

会得到一个类似这样的令牌:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ4aWFvbWluZyIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MzEzNDYxODEsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6IjUzZjcxZTA2LTUzZjktNDk0OC1iYWQxLTM4ZGIzNmI2YmI2NSIsImNsaWVudF9pZCI6ImMxIn0.rmCcyciOFqJyXJbFLWaEXo0U3uU9LO1BaL5bHFUVVD0

最后get请求访问资源服务:

http://127.0.0.1:53021/order/r1?access_token=JWT令牌

至此,OAUTH2.0与JWT令牌的配置应用部分基本上已经完成,其它有什么需求,可自行进行扩展。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Spring Boot、OAuth2.0JWT Token鉴权认证开发的后台接口是一种使用现代化技术实现的身份验证和授权机制。下面是关于这种后台接口的一些说明: 首先,Spring Boot是一个基于Spring框架的快速开发框架,提供了简化的配置和自动化的特性,使开发者能够更快速高效地开发后台接口。 OAuth2.0是一种开放标准的授权协议,它允许用户授权第三方应用访问他们在资源拥有者上存储的信息,而不需要将用户名和密码提供给第三方。 JWT Token(JSON Web Token)是一种用于在网络应用间安全传递声明的一种方式。它被用作身份验证和授权的令牌,通过加密并以JSON格式存储信息,确保信息的完整性和安全性。 基于以上技术,我们可以开发出具有强大安全认证能力的后台接口。首先,用户在访问接口时,需要提供他们的身份证明,这可以是用户名和密码。接口服务器会使用OAuth2.0协议进行身份验证,并颁发JWT Token给用户。用户在未来的请求中,可以使用该Token进行身份验证,而无需每次都提供用户名和密码。 接口服务器会对JWT Token进行验证,以确保Token的完整性和有效性。如果Token失效或被伪造,访问将被拒绝。如果验证通过,接口服务器会正常处理用户的请求。 使用Spring Boot和OAuth2.0进行开发,可以方便地设置权限和角色。可以根据用户的角色和权限,限制他们对某些资源的访问。 总之,基于Spring Boot、OAuth2.0JWT Token鉴权认证开发的后台接口提供了一种安全可靠的身份验证和授权机制,能够有效保护后台接口的安全性,防止非法访问和数据泄露。这种技术组合在开发现代化的网络应用时非常有用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值