欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储

程序员文章站 2022-06-13 19:59:35
...

前面写了如何配置OAuth2 和 SpringSeurity 授权中心,但是使用的内存存储的,以及使用的默认InMemoryTokenStore 普通令牌,这次我们修改为Jwt令牌,并且使用JDBC存储客户端信息。

前一篇文章
OAuth2 和 SpringSecurity完成授权认证中心(一)搭建授权认证

初始化SQL

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
  `client_id` varchar(255) NOT NULL,
  `resource_ids` varchar(255) DEFAULT NULL,
  `client_secret` varchar(255) DEFAULT NULL,
  `scope` varchar(255) DEFAULT NULL,
  `authorized_grant_types` varchar(255) DEFAULT NULL,
  `web_server_redirect_uri` varchar(255) DEFAULT NULL,
  `authorities` varchar(255) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` longtext,
  `create_time` datetime DEFAULT NULL,
  `archived` tinyint(4) DEFAULT NULL,
  `trusted` tinyint(4) DEFAULT NULL,
  `autoapprove` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('c1', 'res1', '$2a$10$LNl3wbdkZX54Tj/9SlxHiOw.a8Iqg0jBplzJcCIbfJVSIPr8mAGvS', 'ROLE_ADMIN,ROLE_USER,ROLE_API', 'client_credentails,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', null, '7200', '259200', null, '2019-11-13 14:20:08', '0', '0', 'false');
INSERT INTO `oauth_client_details` VALUES ('c2', 'res2', '$2a$10$NlBC84MVb7F95EXYTXwLneXgCca6/GipyWR5NHm8K0203bSQMLpvm', 'ROLE_API', 'client_credentails,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', null, '31536000', '259200', null, '2019-11-13 14:21:11', '0', '0', 'false');


SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for oauth_code
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `code` varchar(255) DEFAULT NULL,
  `authentication` blob,
  KEY `code_index` (`code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

修改TokenConfig,改变令牌策略

@Configuration
public class TokenConfig {
    private static final String SIGNING_KEY = "uaa123";
    // 令牌存储策略
    @Bean
    public TokenStore tokenStore()
    {
        // Jwt令牌存储方案
        return new JwtTokenStore(assessTokenConverter());
    }
    @Bean
    public JwtAccessTokenConverter assessTokenConverter()
    {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGNING_KEY);//
        return converter;
    }
}

修改AuthorizationServer.java 类

添加JwtAccessTokenConverter

@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;

修改令牌管理服务方法

// 令牌管理服务
    public AuthorizationServerTokenServices tokenServices()
    {
        DefaultTokenServices service = new DefaultTokenServices();
        service.setClientDetailsService(clientDetailsService);  // 客户端信息服务
        service.setSupportRefreshToken(true);   // 是否产生刷新令牌
        service.setTokenStore(tokenStore);  // 设置令牌存储策略
        // 令牌增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
        service.setTokenEnhancer(tokenEnhancerChain);
        service.setAccessTokenValiditySeconds(7200);// 令牌默认有效期 2 小时
        service.setRefreshTokenValiditySeconds(259200);
        return service;
    }

配置 客户端Jdbc详细信息


    private AuthorizationCodeServices authorizationCodeServices;
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource)
    {
        return new JdbcAuthorizationCodeServices(dataSource);
    }
    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;
    
	@Bean
    public ClientDetailsService clientDetailsService(DataSource dataSource)
    {
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        clientDetailsService.setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

配置修改客户端详细信息方法

 // 配置客户端详细信息
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.withClientDetails(clientDetailsService);

    }

最终AuthorizationServer 类

@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource)
    {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;


    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Bean
    public ClientDetailsService clientDetailsService(DataSource dataSource)
    {
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        clientDetailsService.setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }


    // 配置客户端详细信息
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.withClientDetails(clientDetailsService);

    }



    // 令牌管理服务
    public AuthorizationServerTokenServices tokenServices()
    {
        DefaultTokenServices service = new DefaultTokenServices();
        service.setClientDetailsService(clientDetailsService);  // 客户端信息服务
        service.setSupportRefreshToken(true);   // 是否产生刷新令牌
        service.setTokenStore(tokenStore);  // 设置令牌存储策略
        // 令牌增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
        service.setTokenEnhancer(tokenEnhancerChain);
        service.setAccessTokenValiditySeconds(7200);// 令牌默认有效期 2 小时
        service.setRefreshTokenValiditySeconds(259200);
        return service;
    }

  

    /**
     *  令怕i访问端点
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                // 密码管理模式
                .authenticationManager(authenticationManager)
                // 授权码模式
                .authorizationCodeServices(authorizationCodeServices)
                .tokenServices(tokenServices()) // 令牌管理服务
                .allowedTokenEndpointRequestMethods(HttpMethod.POST); // 允许post提交
    }


    /**
     *  令牌访问端点的安全策略
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")         // /oauth/token_key  公开
                .checkTokenAccess("permitAll()")       // /auth/check_token  检测令牌
                .allowFormAuthenticationForClients();  // 允许通过表单认证,申请令牌

    }
}

修改order 服务

TokenConfig.java

@Configuration
public class TokenConfig{

    private static final String SIGNING_KEY = "uaa123";

    // 令牌存储策略
    @Bean
    public TokenStore tokenStore()
    {
        // Jwt令牌存储方案
        return new JwtTokenStore(assessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter assessTokenConverter()
    {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGNING_KEY);//
        return converter;
    }
}

修改ResourceServerConfig.java 文件
all 修改为数据库中scope字段中一个 ROLE_ADMIN

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

因为要使用本地 检查token 所以 将 tokenServices 注释掉

最终配置类
ResourceServerConfig

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    public static final String RESOURCE_ID = "res1";

    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**").access("#oauth2.hasScope('ROLE_ADMIN')")
                .and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        super.configure(http);
    }
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(RESOURCE_ID) // 资源id
                .tokenStore(tokenStore)
                .stateless(true);
    }
}

依次启动 UaaJwtServerOrderJwtServer

使用postman 进行测试
通过浏览器 地址栏获取 code 的值
OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储
点击Authorize 获取 code. 查看数据库
OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储
回调的百度链接后带的code
OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储
获取token。 OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储
携带token 去访问有的 资源
OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储

一、简化模式

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

参数描述和授权码模式,注意reponse_type=token, 说明是 简化模式

二、密码模式

POST

/uaa//oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=zhangsan&password=123

  1. 资源拥有者将用户名 密码发给客户端
  2. 客户端拿着资源拥有者的用户名,密码向服务器请求令牌
  3. 授权服务器将令牌发送给client

参数列表:

  • client_id : 客户端标识
  • client_secret: 客户端**
  • grant_tyoe: 授权类型 填写password 表示 密码模式
  • username: 用户名
  • password: 密码
三、客户端模式

POST

/uaa/oath/token?grant_type=client_credentials&client_id=c1&client_secret=secret

  1. 客户端向授权服务器发送自己的身份呢信息,并请求令牌
  2. 确认客户端身份无误,将颁发令牌给客户端

参数列表

  • client_id:客户端标识
  • client_secret: 客户端**
  • grant_type: 授权类型, client_credentials 表示客户端模式