SpringBoot集成oauth2(客户端模式)

客户端模式:
请求一个接口,咱们的后端服务A直接请求验证服务B拿到token,服务A再用token访问资源服务C。

这里用模块化开发,一个资源服务器,一个验证服务器
在这里插入图片描述

依赖

Springboot 版本为2.3.3.RELEASE

<!--Security + oauth2 + jwt -->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.security.oauth</groupId>
     <artifactId>spring-security-oauth2</artifactId>
     <version>2.5.0.RELEASE</version>
 </dependency>
 <dependency>
     <groupId>org.springframework.security</groupId>
     <artifactId>spring-security-jwt</artifactId>
     <version>1.1.1.RELEASE</version>
 </dependency>
 <dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.1</version>
 </dependency>
 <dependency>
     <groupId>com.sun.xml.ws</groupId>
     <artifactId>jaxws-rt</artifactId>
     <version>2.3.3</version>
 </dependency>

 <!--redis + 连接池-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
 <dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-pool2</artifactId>
 </dependency>

yml

server:
  port: 9910
myoauth2:
  clientId: admin1
  clientSecret: 123456
  tokenEndpoint: http://localhost:9910

1.配置一个验证服务器 9910 端口

/**
 * 验证服务器;EnableAuthorizationServer注解表示是个验证服务器
 */
@Configuration
@EnableAuthorizationServer
public class Config_Authorization extends AuthorizationServerConfigurerAdapter {

    @Value("${myoauth2.clientId}")
    private String clientId;
    @Value("${myoauth2.clientSecret}")
    private String clientSecret;

    private static final String DEMO_RESOURCE_ID = "order";

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private BCryptPasswordEncoder passwordEncoder;

//============redis存储token===============
//    @Resource
//    private RedisConnectionFactory redisConnectionFactory;
//============redis存储token===============
 
 
    //=============JWT存储token==================
    @Resource
    private TokenStore tokenStore;
    @Resource
    private JwtAccessTokenConverter accessTokenConverter;
    @Resource
    private Jwt_TokenEnhancer jwtTokenEnhancer;
    //=============JWT存储token==================


    /**
     * 访问端点配置
     * 配置授权authorization以及令牌(token)的访问端点和令牌服务(token services)
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //配置Redis存储token
        //endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory));

        //配置Jwt存储token + Jwt自定义增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, accessTokenConverter));
        endpoints.tokenStore(tokenStore).accessTokenConverter(accessTokenConverter).tokenEnhancer(tokenEnhancerChain);

        //配置管理器允许GET和POST请求端点oauth/token获取Token
        endpoints.authenticationManager(authenticationManager).allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }

    /**
     * 授权端点开放,配置令牌端点(Token Endpoint)的安全约束
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .tokenKeyAccess("permitAll()")              //开启/oauth/token_key验证端口无权限访问
                .checkTokenAccess("isAuthenticated()")      //开启/oauth/check_token验证端口认证权限访问
                .allowFormAuthenticationForClients();       //允许表单认证
    }

    /**
     * 配置客户端详情服务
     * 客户端详情信息在这里进行初始化, 通过数据库来存储调取详情信息
     * 在验证服务器为客户端client配置resourceIds的目的是:限制某个client可以访问的资源服务。
     * 当请求发送到Resource Server的时候会携带access_token,
     * Resource Server会根据access_token找到client_id,进而找到该client可以访问的resource_ids。
     * 如果resource_ids包含ResourceServer自己设置ResourceID,这关就过去了,就可以继续进行其他的权限验证
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //使用内存模式; 也可以配置客户端存储到数据库DB,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息
        clients.inMemory()
                .withClient(clientId)                                                   //client_id
                .secret(passwordEncoder.encode(clientSecret))                           //client_密码
                .resourceIds(DEMO_RESOURCE_ID)                                          //配置资源的id
                .authorizedGrantTypes("client_credentials")                             //授权类型:客户端模式
                .scopes("all")                                                          //配置申请的权限范围
                .authorities("client");                                                 //客户端可以使用的权限

    }
}

2. Security配置类


@Configuration
@EnableWebSecurity
public class Config_WebSecurity extends WebSecurityConfigurerAdapter {


    /**
     * 配置拦截保护的请求径
     * permitAll() 表示任意用户可访问
     * anyRequest() 表示所有请求
     * authenticated() 表示已登录用户才能访问
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()                                                                 //不启用跨站请求伪造
                .disable()
                .authorizeRequests()
                .antMatchers("/oauth/**", "/login/**", "/logout/**")    //放行这些以"/login/","/oauth/"开头请求
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll();
    }

    /**
     * 配置验证管理器
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 配置密码加密器
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

验证服务器用JWT存储Token,返回JWT格式的Token

/**
 * 使用Jwt存储token的配置
 */
@Configuration
public class Jwt_TokenStore {

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

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

    @Bean
    public Jwt_TokenEnhancer jwtTokenEnhancer() {
        return new Jwt_TokenEnhancer();
    }
}

JWT内容自定义


/**
 * Jwt内容增强器
 */
public class Jwt_TokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Map<String, Object> info = new HashMap<>();
        info.put("我的信息", "abcddd");
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}

再配置一个资源服务器 9911 端口

@Slf4j
@Configuration
@EnableResourceServer
public class Config_Resource extends ResourceServerConfigurerAdapter {

    @Value("${uaa.clientId}")
    private String clientId;
    @Value("${uaa.clientSecret}")
    private String clientSecret;
    @Value("${uaa.tokenEndpoint}")
    private String tokenEndpoint;

    /**
     * ResourceID资源的标识
     */
    private static final String DEMO_RESOURCE_ID = "order";

    /**
     * 在每个ResourceServer实例上设置resourceId,该resourceId作为该资源的唯一标识
     * 验证服务器给Client第三方客户端授权时,可以设置这个Client可以访问哪些Resource-Server资源服务
     * 如没有设置就是对所有的Resource-Server都有访问权限
     *
     * resources.resourceId(DEMO_RESOURCE_ID)     //为每个ResourceServer(一个微服务实例)设置一个ResourceID
     * resources.stateless(true)                  //标记以指示在这些资源上仅允许基于令牌的身份验证
     * resources.tokenStore(xxx)                  //token的存储方式
     * resources.tokenExtractor(xxx)              //token获取方式,默认为BearerTokenExtractor
     * resources.authenticationEntryPoint(xxx);   //配置自定义的认证异常处理返回类
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(DEMO_RESOURCE_ID).stateless(true);
    }

    /**
     * 用来配置拦截保护的请求
     * 这里可以代替Spring Security同名方法配置
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()                       //禁用了csrf功能,关跨域保护
                .authorizeRequests()                //限定签名成功的请求
                .antMatchers("/order/**").authenticated()  //必须认证过后才可以访问
                .anyRequest().permitAll()       //其他没有限定的请求允许随意访问
                .and().anonymous();             //对于没有配置权限的其他请求允许匿名访问

    }

    /**
     * RemoteTokenServices是用于向远程认证服务器验证token,同时获取token对应的用户的信息
     * 通过RestTemplate调用远程服务,我们在使用这个类时,要设置checkTokenEndpointUrl、clientId、clientSecret等。
     * 只需要显示注入RemoteTokenServices remoteTokenServices()的Bean就可以调用授权服务器的/oauth/check_token端点查询token的合法性,之后返回其信息
     * 设置客户端配置的值
     */
    @Primary
    @Bean
    public RemoteTokenServices remoteTokenServices() {
        final RemoteTokenServices tokenServices = new RemoteTokenServices();
        //设置授权服务器check_token(验证token)端点完整地址
        tokenServices.setCheckTokenEndpointUrl(tokenEndpoint+"/oauth/check_token");
        //设置client_id与secret,注意client_secret值不能使用passwordEncoder加密
        tokenServices.setClientId(clientId);
        tokenServices.setClientSecret(clientSecret);
        return tokenServices;
    }
}

已经配好了,启动两个服务
在这里插入图片描述
验证服务器9910,资源服务器9911
上面的保护资源的是order,要请求资源服务器order接口时需要token验证
这里先访问资源服务器的接口
在这里插入图片描述

首先用户要访问order资源,
我们后台服务器A 通过过滤器 先去验证服务器B拿Token
http://localhost:9910/oauth/token?grant_type=client_credentials&scope=select&client_id=admin1&client_secret=123456

这就要求验证服务器B对我们的服务器A很信任
请求Token返回的结果中有access_token
这时服务A再访问资源服务器C,请求头中自动添加这个参数:Authorization 值为access_token 或者 "Bearer "+access_token;就可以访问order了

当然资源服务器C收到了带Token的请求先会去验证服务器B验证一下Token对不对
就是RemoteTokenServices 这个方法,远程调用验证端点check_token了

这种模式不常用,一般用密码模式和授权码模式

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spring Boot 中的 OAuth 客户端配置需要在配置文件中进行配置,一般使用 application.properties 或 application.yml 文件。常用的配置有: 1. 客户端 ID 和密钥:spring.security.oauth2.client.client-id 和 spring.security.oauth2.client.client-secret 2. 认证服务器地址:spring.security.oauth2.client.provider.{provider}.authorization-uri 和 spring.security.oauth2.client.provider.{provider}.token-uri 3. 回调地址:spring.security.oauth2.client.registration.{registration}.redirect-uri 其中 {provider} 是服务提供商的名称,如 google、github 等;{registration} 是当前应用在认证服务器上的注册名称。 具体配置可以参考 Spring Boot 官方文档中的相关章节:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-security-oauth2-client ### 回答2: Spring Boot中的OAuth客户端配置是指在使用Spring Boot框架开发应用程序时,如何配置应用程序作为OAuth 2.0的客户端来实现授权和认证功能。 在Spring Boot中配置OAuth客户端通常需要以下步骤: 1. 添加依赖:在`pom.xml`文件中添加相应的依赖,例如可以使用`spring-boot-starter-oauth2-client`。 2. 配置属性:在`application.properties`或`application.yml`文件中配置OAuth客户端的属性,例如设置授权服务器的URL、客户端ID和密钥等。 3. 创建认证回调URL:在应用程序中创建一个认证回调URL,在该URL上回接收来自授权服务器的授权码或访问令牌等信息。 4. 配置认证配置类:创建一个OAuth2的配置类,用于配置认证服务器的信息和认证管理器等。 5. 配置安全规则:根据应用程序的需求,可以配置一些安全规则,例如哪些URL需要进行认证、哪些URL可以匿名访问等。 6. 使用OAuth客户端:在需要使用OAuth客户端的地方,例如请求API资源时,可以使用`RestTemplate`或`Feign Client`等工具进行请求,并在请求中携带认证信息。 以上是Spring Boot中配置OAuth客户端的一般步骤,当然具体的配置和使用方式可能会根据实际需求有所不同。通过合理的配置,我们可以在Spring Boot应用程序中使用OAuth 2.0协议来实现用户认证和授权等功能。 ### 回答3: 在Spring Boot中配置OAuth客户端实际上是配置一个被保护资源的客户端应用程序,以便与OAuth 2.0服务器进行交互。以下是配置Spring Boot中OAuth客户端的步骤: 1. 添加依赖:在项目的pom.xml文件中添加Spring Security OAuth2客户端的相关依赖,例如spring-security-oauth2-autoconfigure和spring-security-oauth2-client。 2. 创建应用程序配置:在application.properties或application.yml文件中设置应用程序的配置,包括OAuth服务提供商的URL、客户端ID和客户端密钥等信息。 3. 配置Security:在Spring Security配置类中,使用@EnableOAuth2Client注解启用OAuth2客户端,并配置ClientRegistrationRepository bean,用于存储和管理客户端应用程序的注册信息。 4. 配置客户端注册信息:在应用程序配置类中,使用@Bean注解创建ClientRegistration对象,指定客户端应用程序的注册信息,包括客户端ID、客户端密钥、授权范围、授权服务器地址等。 5. 配置授权规则:使用@EnableWebSecurity注解将应用程序的安全性配置为基于OAuth2的安全协议。定义的授权规则可以通过.antMatchers()和.permitAll()等来配置。 6. 处理回调URL:配置回调URL,用于接收授权服务器返回的授权码,并将其交给授权提供商进行令牌交换。 7. 配置用户信息获取:使用UserDetailsService接口的实现类,获取授权提供商返回的用户信息,并进行相应的处理。 通过以上步骤,我们就可以在Spring Boot中成功配置一个OAuth客户端,使得应用程序能够与OAuth 2.0服务器进行交互,获取受保护资源的授权。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值