oauth2-令牌使用jwt字符串并且自定义Token数据

1.项目结构图

在这里插入图片描述

2.建表语句

DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details`  (
  `client_id` varchar(48) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `resource_ids` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `client_secret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `authorized_grant_types` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `web_server_redirect_uri` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `access_token_validity` int(11) NULL DEFAULT NULL,
  `refresh_token_validity` int(11) NULL DEFAULT NULL,
  `additional_information` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `autoapprove` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('yl', 'res1', '$2a$10$O8G0X/sUPAA76MV7U3BwY.3Uo8/QMBcqK678Rwkoz.fowbce.CLtO', 'all', 'authorization_code,refresh_token,implicit,password,client_credentials', 'http://localhost:8082/01.html,http://localhost:8082/02.html', NULL, 7200, 7200, NULL, 'true');

SET FOREIGN_KEY_CHECKS = 1;

3.授权服务器的搭建(auth-server)

1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yl</groupId>
    <artifactId>auth-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>auth-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-security</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.main.allow-bean-definition-overriding=true

# redis的配置
spring.redis.host=192.168.244.138
spring.redis.port=6379
spring.redis.password=root123
spring.redis.database=0


3.token的配置

package com.yl.authserver.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

@Configuration
public class AccessTokenConfig {

    // 服务端不需要保存jwt的字符串
    @Bean
    TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("tom");
        return converter;
    }
}

4.security的配置

package com.yl.authserver.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password(passwordEncoder().encode("123"))
                .roles("admin")
                .and()
                .withUser("root")
                .password(passwordEncoder().encode("123"))
                .roles("root");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().formLogin();
    }
}

5.自定义token数据返回的配置

package com.yl.authserver.config;

import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class AdditionalInformation implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Map<String, Object> map = oAuth2AccessToken.getAdditionalInformation();
        map.put("msg","hello oauth2");
        map.put("网站","www.baidu.com");
        map.put("微信","66");
        ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(map);
        return oAuth2AccessToken;
    }
}

6.授权服务器的配置

package com.yl.authserver.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.code.InMemoryAuthorizationCodeServices;
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 AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    TokenStore tokenStore;
    // 客户端信息
//    @Autowired
//    ClientDetailsService clientDetailsService;
    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    JwtAccessTokenConverter jwtAccessTokenConverter;
    @Autowired
    AdditionalInformation additionalInformation;
    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    DataSource dataSource;

    @Bean
    ClientDetailsService clientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }

    //配置Token服务
    AuthorizationServerTokenServices authorizationServerTokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setClientDetailsService(clientDetailsService());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setAccessTokenValiditySeconds(60 * 60 * 2); //token有限期设置为2小时
        tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);
        tokenServices.setTokenStore(tokenStore);
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter,additionalInformation));
        tokenServices.setTokenEnhancer(tokenEnhancerChain);
        return tokenServices;
    }

    //配置token
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()")// /oauth/check_token   带时候会调用这个请求来校验token
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();

    }

    //配置客户端的信息(客户端信息存于内存)
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.inMemory()
//                .withClient("yl") //客户端名
//                .secret(passwordEncoder.encode("123")) //客户端密码
//                .scopes("all")
//                .resourceIds("res1") //资源id
//                .authorizedGrantTypes("authorization_code","refresh_token","implicit","password","client_credentials")
//                // authorization_code授权码模式,password密码模式,implicit简化模式,client_credentials客户端模式,可以设置同时支持多种模式
//                .autoApprove(true) //自动授权
                .redirectUris("http://localhost:8082/index.html"); //授权码模式界面
                .redirectUris("http://localhost:8082/01.html");//简化模式界面
//                .redirectUris("http://localhost:8082/02.html");//密码模式界面
//    }

    //配置客户端的信息(客户端信息存于数据库)
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       clients.withClientDetails(clientDetailsService());
    }

    //配置端点信息(主要获取授权码,要先拿到授权码,然后再根据授权码去获取token)
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authorizationCodeServices(authorizationCodeServices())
                .authenticationManager(authenticationManager)
                .tokenServices(authorizationServerTokenServices());
    }

    @Bean
    AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }
}

4. 资源服务器的搭建(user-server)

1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yl</groupId>
    <artifactId>user-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-security</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.application.properties

server.port=8081

3.contoller

package com.yl.userserver.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin(value = "*")
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

    @GetMapping("/admin")
    public String admin() {
        return "hello admin";
    }
}

4.token的配置

package com.yl.userserver.config;

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 AccessTokenConfig {

    // 服务端不需要保存jwt的字符串
    @Bean
    TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("tom");
        return converter;
    }
}

5.资源服务器的配置

package com.yl.userserver.config;

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.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.TokenStore;

//配置资源服务器
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    TokenStore tokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("res1")
                .tokenStore(tokenStore)
                .stateless(true);

    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**")
                .hasRole("admin")
                .anyRequest().authenticated()
                .and().cors();
    }
}

5. 测试

1.启动redis
2.启动授权服务器和资源服务器
3.获取token
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.携带token访问资源服务器的hello接口
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: OAuth 2.0是一种授权框架,用于授权第三方应用程序访问用户在其他应用程序上的资源。当用户使用OAuth 2.0登录并授权后,被请求访问的资源将生成一个访问令牌(access token),用于后续的访问请求。 JWT(JSON Web Token)是一种用于在不同系统之间安全传输信息的标准。它是由三部分组成的字符串,包括头部(header)、载荷(payload)和签名(signature)。其中,载荷部分包含一些声明性的信息,用于标识用户或其他相关信息。签名部分则用于验证令牌的真实性和完整性。 单点登录(Single Sign-On,简称SSO)是一种身份验证机制,在一次登录后,允许用户访问多个相关系统,而无需重新进行身份验证。当用户进行初始身份验证后,一个包含JWT令牌将生成并返回给用户。 想要获得JWT,用户需要先通过OAuth 2.0进行身份验证和授权。用户在第三方应用程序上进行登录,该应用程序将向授权服务器发送身份验证请求。授权服务器将验证用户的身份并颁发访问令牌。然后,用户将该令牌发送到资源服务器上进行鉴权。资源服务器将验证令牌的有效性,并使用私钥对JWT进行签名,保证其真实性。最后,资源服务器会返回给用户一个含有JWT的响应。 用户在后续的访问请求中,只需携带JWT即可进行授权,无需再次进行身份验证。资源服务器接收到带有JWT的请求后,将对其进行验证,并根据令牌中的声明信息进行相应的授权操作。 通过OAuth 2.0和JWT,单点登录实现了用户在多个应用程序之间的无缝访问,提供了便捷的用户体验和更高的安全性。 ### 回答2: OAuth 2.0是一种用于授权的开放标准,用于允许用户提供给第三方应用程序已授权访问特定资源的权限。它使用Access Token来表示用户的授权凭证。 要获得JWT(JSON Web Token),首先需要进行OAuth 2.0的认证和授权流程。以下是一般的流程: 1. 用户访问应用程序,并选择使用单点登录进行身份验证。 2. 应用程序将用户重定向到认证服务器,以获取授权。 3. 用户在认证服务器上登录,并确认授权访问应用程序所需的资源。 4. 认证服务器将授权码(Authorization Code)传递给应用程序的回调URL。 5. 应用程序使用授权码向认证服务器请求访问令牌(Access Token)。 6. 认证服务器验证应用程序的身份,并向应用程序颁发访问令牌。 7. 应用程序将访问令牌保存在安全的位置,以供将来的API调用使用。 8. 应用程序使用访问令牌向API服务器请求受保护资源。 9. API服务器对访问令牌进行验证,并返回请求的资源。 10. 如果访问令牌有效,则应用程序可以将其作为JWT进行使用。 获得JWT的过程实际上是通过OAuth 2.0的授权流程获得访问令牌,然后将访问令牌转换为JWT格式。JWT是一种用JSON表示的安全令牌,它包含有关用户身份、权限和其他相关信息的声明。 在将访问令牌转换为JWT时,应用程序需要使用加密算法(如HMAC或RSA)对访问令牌进行签名,以确保令牌的完整性和安全性。 总之,要获得JWT,首先需要进行OAuth 2.0的认证和授权流程,获取访问令牌,然后将访问令牌转换为JWT格式。JWT可以用于实现单点登录和安全访问控制。 ### 回答3: OAuth 2.0和JWT是用于实现单点登录的两种常见的身份验证和授权机制。下面是关于如何获得JWT的简要解释。 在OAuth 2.0流程中,客户端首先将用户重定向到认证服务器以进行身份验证。用户成功登录后,认证服务器将授权码返回给客户端。接下来,客户端使用该授权码请求访问令牌,同时提供其客户端凭据。认证服务器根据验证客户端凭据,并验证授权码的有效性后,颁发一个访问令牌给客户端。访问令牌可以用于访问受保护的资源服务器。然而,JWT并不是OAuth 2.0规范的一部分,它是作为一种安全令牌的表示形式,可以用于在认证(Authentication)和授权(Authorization)之间传输和存储信息。 在实现单点登录中,当用户通过身份验证获得访问令牌后,应用程序使用令牌向身份提供者(例如认证服务器)请求JWT令牌。身份提供者使用该访问令牌生成一个JWT令牌,并将其返回给应用程序作为响应。这个JWT令牌包含有关用户身份的信息。应用程序可以将该令牌存储在客户端的会话中,以便在其他资源服务器上验证用户身份时使用。 获得JWT的过程需要通过OAuth 2.0进行授权并使用访问令牌来请求JWT令牌。要么应用程序直接与身份提供者交互来获取JWT,要么使用一些第三方库或框架来实现该过程。无论是直接与身份提供者交互还是使用第三方库,都需要遵循OAuth 2.0和JWT的相应规范和流程,以确保安全性和正确性。 总之,获得JWT的过程包括通过OAuth 2.0获得访问令牌,并用该令牌向身份提供者请求生成JWT令牌。这个JWT令牌可以用于实现单点登录,并在其他资源服务器上验证用户身份。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值