栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

519、Java Spring Cloud Alibaba -【Spring Cloud Alibaba Oauth2 - 下】 2021.11.01

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

519、Java Spring Cloud Alibaba -【Spring Cloud Alibaba Oauth2 - 下】 2021.11.01

目录
    • 1、搭建 Oauth2 资源服务(客户端)
    • 2、Feign 微服务间调用认证踩坑
    • 3、参考链接

1、搭建 Oauth2 资源服务(客户端)

搭建下边几个服务任选一个:

会员服务:herring-member-service,微服务之一,接收到请求后会到认证中心验证。
订单服务:herring-orders-service,微服务之二,接收到请求后会到认证中心验证。
商品服务:herring-product-service,微服务之三,接收到请求后会到认证中心验证。
添加 pom 文件依赖:

        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
        

如果在 jwt 中加入了额外信息,而在接收到 jwt 格式的 token 之后,用户客户端要把 jwt 解析出来。

        
            io.jsonwebtoken
            jjwt
            0.9.1
        

1.1 application.yml 配置文件:

client-id、client-secret 要和认证服务中的配置一致,
access-token-uri 是密码模式需要用到的获取 token 的接口,
user-authorization-uri 是授权码认证方式需要的,可以不设置。

server:
  port: 10801
  servlet:
    context-path: /api/member

spring:
  application:
    name: member-service
    
security:
  oauth2:
    client:
      client-id: app-client
      client-secret: client-secret-8888
      user-authorization-uri: http://localhost:10800/oauth/authorize
      access-token-uri: http://localhost:10800/oauth/token
    resource:
      jwt:
        key-uri: http://localhost:10800/oauth/token_key
        key-value: sign-8888

1.2 ResourceServerConfig 类的配置:

资源服务的注解 @EnableResourceServer,注意 JwtAccessTokenConverter 设置的 signingKey 要和配置文件中的 key-value 相同,不然会导致无法正常解码 jwt ,导致验证不通过。

server:
  port: 10801
  servlet:
    context-path: /api/member

spring:
  application:
    name: member-service
    
security:
  oauth2:
    client:
      client-id: app-client
      client-secret: client-secret-8888
      user-authorization-uri: http://localhost:10800/oauth/authorize
      access-token-uri: http://localhost:10800/oauth/token
    resource:
      jwt:
        key-uri: http://localhost:10800/oauth/token_key
        key-value: sign-8888

1.3 ResourceServerConfig 类的配置:

资源服务的注解 @EnableResourceServer,注意 JwtAccessTokenConverter 设置的 signingKey 要和配置文件中的 key-value 相同,不然会导致无法正常解码 jwt ,导致验证不通过。

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class JwtResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Resource
    private TokenStore jwtTokenStore;

    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
        accessTokenConverter.setSigningKey("sign-8888");
        accessTokenConverter.setVerifierKey("sign-8888");
        return accessTokenConverter;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(jwtTokenStore);
        resources.resourceId("member-service");
    }

}

1.4 HelloController 创建几个测试用的接口:

@RestController
@RequestMapping
public class HelloController {

    @Resource
    private MemberService memberService;

    @RequestMapping("/service")
    public String service() {
        return memberService.sayHello();
    }

    @GetMapping(value = "/info/jwt")
    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    public Object jwtParser(Authentication authentication) {
        authentication.getCredentials();
        OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
        String jwtToken = details.getTokenValue();
        Claims claims = Jwts.parser()
                .setSigningKey("sign-8888".getBytes(StandardCharsets.UTF_8))
                .parseClaimsJws(jwtToken)
                .getBody();
        return claims;
    }

}

@Service
public class MemberService {

    public String sayHello() {
        return "Hello, Member! ";
    }

}

1.5 启动资源服务,测试 Oauth2 的密码模式流程:

一、向 Oauth2 认证中心(服务端)请求 token:
向 Oauth2 认证中心(服务端)请求 token

POST http://localhost:10800/oauth/token?grant_type=password&username=admin&password=123456&client_id=app-client&client_secret=client-secret-8888&scope=all
Accept: **
Cache-Control: no-cache

得到请求结果:

{
  "error": "unauthorized",
  "error_description": "Full authentication is required to access this resource"
}

请求带错误的 token:

#### 向 Oauth2 资源服务(客户端)请求数据

GET http://localhost:10801/api/member/service
Accept: **
Cache-Control: no-cache
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsInByb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTYxMjg1ODQxNywiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJiMGQ5ZTI1Yy1jZGE3LTQ4MDctOWJmZS02ZjcyYjM4NGVhNTMiLCJjbGllbnRfaWQiOiJhcHAtY2xpZW50In0.w4M9zCahAVISQ_wfKdkT6n9Aaw6kFtoh5HmCJ_uy-vU

得到请求结果:

Hello, Member! 

三、向 Oauth2 认证中心(服务端)刷新 token:

#### 向 Oauth2 认证中心(服务端)刷新 token

POST http://localhost:10800/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsInByb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6ImIwZDllMjVjLWNkYTctNDgwNy05YmZlLTZmNzJiMzg0ZWE1MyIsImV4cCI6MTYxMjkyMzIxNywiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiIzZmQ2MWM4ZS1kNTcyLTQ0YjYtYjViNC0zMzc3ODQ5NjY4YmQiLCJjbGllbnRfaWQiOiJhcHAtY2xpZW50In0.WxisDVLUlfP45pepc4sQM1M7UCvzsET0O8JvF11tKAI&client_id=app-client&client_secret=client-secret-8888
Accept: **
Cache-Control: no-cache
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsInByb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTYxMjg1OTQxMSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJkYWVlNjlkZi02NTFhLTQ1MmItYjA0Yi05N2FhYTc2MjkzYTgiLCJjbGllbnRfaWQiOiJhcHAtY2xpZW50In0.F30LZplYodM7zH0N6gwBA29uCBObZISgOPXf-PKB3aI

得到请求结果:

Hello, Member! 

四、向 Oauth2 资源服务(客户端)请求查看具体 jwt 的 token 解码内容:

#### 向 Oauth2 资源服务(客户端)请求查看具体 jwt 的 token 解码内容

GET http://localhost:10801/api/member/info/jwt
Accept: **
Cache-Control: no-cache
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsInByb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTYxMjg1OTQxMSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJkYWVlNjlkZi02NTFhLTQ1MmItYjA0Yi05N2FhYTc2MjkzYTgiLCJjbGllbnRfaWQiOiJhcHAtY2xpZW50In0.F30LZplYodM7zH0N6gwBA29uCBObZISgOPXf-PKB3aI

得到请求结果:

{
  "timestamp": 1612855021645,
  "status": 500,
  "error": "Internal Server Error",
  "message": "[401] during [GET] to [http://product-service/api/product/service] [ProductClient#service()]: [{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}]",
  "path": "/api/member/hello"
}

为什么呢?我明明 http 请求头里带了正确的 token,却报 401 forbidden 的错误信息。

原因是 当我请求数据 /api/member/hello 时,虽然 http 请求头里带了正确的 token,但是在远程调用
orders-service,product-service 服务时,feign 新建的请求并不会带上这个 token,这是两个不同的
http 请求,所以就会导致 401 forbidden 的错误信息。

解决方案就是在 member-service,orders-service,product-service 都添加一个 RequestInterceptor:

public class TokenRelayRequestInterceptor implements RequestInterceptor {

    public static final String AUTH_TOKEN = "Authorization";

    @Override
    public void apply(RequestTemplate template) {
        // 获取该次请求得token 将token传递
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(AUTH_TOKEN);
        if (!StringUtils.isEmpty(token)) {
            template.header(AUTH_TOKEN, token);
        }
    }

}

并且在 application.yml 中添加配置:

feign:
  client:
    config:
      default:
        requestInterceptors:
          - com.herring.feign.interceptor.TokenRelayRequestInterceptor

7.带正确的 token,再次向 Oauth2 资源服务(客户端)请求数据 /api/member/hello:

#### 向 Oauth2 资源服务(客户端)请求数据

GET http://localhost:10801/api/member/hello
Accept: */*
Cache-Control: no-cache
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsInByb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTYxMjg1OTQxMSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJkYWVlNjlkZi02NTFhLTQ1MmItYjA0Yi05N2FhYTc2MjkzYTgiLCJjbGllbnRfaWQiOiJhcHAtY2xpZW50In0.F30LZplYodM7zH0N6gwBA29uCBObZISgOPXf-PKB3aI

得到请求结果:

Hello, Member! Hello, Product! Hello, Orders! 
3、参考链接

[01] Spring Cloud Alibaba Oauth2

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/390095.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号