Spring Cloud系列 Spring Cloud OAuth2密码模式(resource owner password credentials)

OAuth 2 有四种授权模式,分别是授权码模式(authorization code)、简化模式(implicit)、密码模式(resource owner password credentials)、客户端模式(client credentials),具体 OAuth2 是什么,可以参考这篇文章(http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html)
————————————————
上篇讲解的是授权码模式,本篇主要讲解密码模式。平常主要使用的就是这两种模式。(注:本篇基于上一篇的代码基础之上)

1.授权流程

1.客户端带着clientid,screteid,用户名,密码。到授权服务器获取token。

2.客户端获取到token之后,带着token访问服务。

3.服务获取客户端带过来的token,到授权服务器进行验证token的合法性。有效允许访问服务,无效反之。就是如此简单。

到这。我们开发人员需要实现的就第一,第二步。第三步由我们配置验证url,Spring Cloud OAuth2框架会自动帮我们完成验证。

项目组成authe-server 权限验证服务在上一篇博客已经实现,本篇只需要事项client-user用户需要访问的服务。

Spring Cloud系列 Spring Cloud OAuth2密码模式(resource owner password credentials)_第1张图片

DemoApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}
ResourceServerConfig.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
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;

/**
 * Created by Administrator on 2020-06-12.
 */
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {


//    @Value("${security.oauth2.client.client-id}")
//    private String clientId;
//
//    @Value("${security.oauth2.client.client-secret}")
//    private String secret;
//
//    @Value("${security.oauth2.authorization.check-token-access}")
//    private String checkTokenEndpointUrl;
//
//    @Autowired
//    private RedisConnectionFactory redisConnectionFactory;
//
//    @Bean
//    public TokenStore redisTokenStore (){
//        return new RedisTokenStore(redisConnectionFactory);
//    }
//
//    @Bean
//    public RemoteTokenServices tokenService() {
//        RemoteTokenServices tokenService = new RemoteTokenServices();
//        tokenService.setClientId(clientId);
//        tokenService.setClientSecret(secret);
//        tokenService.setCheckTokenEndpointUrl(checkTokenEndpointUrl);
//        return tokenService;
//    }
//
//    @Override
//    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//        resources.tokenServices(tokenService());
//    }


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

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();

        accessTokenConverter.setSigningKey("dev");
        accessTokenConverter.setVerifierKey("dev");
        return accessTokenConverter;
    }

    @Autowired
    private TokenStore jwtTokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(jwtTokenStore);
    }

}
UserController.java

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;

/**
 * Created by Administrator on 2020-06-12.
 */
@RestController
public class UserController {
    @GetMapping(value = "get")
    //@PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    public Object get(Authentication authentication){
        //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        authentication.getCredentials();
        OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails();
        String token = details.getTokenValue();
        return token;
    }

    @GetMapping(value = "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("dev".getBytes(StandardCharsets.UTF_8))
                .parseClaimsJws(jwtToken)
                .getBody();
        return claims;
    }
}

application.properties 

spring.application.name=client-user
server.port=6101
server.servlet.context-path=/client-user

spring.redis.database=2
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=100ms



security.oauth2.client.client-id=user-client
security.oauth2.client.client-secret=user-secret-8888
security.oauth2.client.user-authorization-uri=http://localhost:6001/oauth/authorize
security.oauth2.client.access-token-uri=http://localhost:6001/oauth/token

#security.oauth2.resource.id=user-client
#security.oauth2.resource.user-info-uri=user-info

security.oauth2.resource.jwt.key-uri=http://localhost:6001/oauth/token_key
security.oauth2.resource.jwt.key-value=dev
security.oauth2.authorization.check-token-access=http://localhost:6001/oauth/check_token

eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/

 pom.xml



	4.0.0
	
		org.springframework.boot
		spring-boot-starter-parent
		2.0.0.RELEASE
		 
	
	com.example
	demo
	0.0.1-SNAPSHOT
	demo
	Demo project for Spring Boot

	
		1.8
	


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

		
			org.springframework.boot
			spring-boot-starter-test
			test
			
				
					org.junit.vintage
					junit-vintage-engine
				
			
		


		
		
		
		


		
		
			org.springframework.cloud
			spring-cloud-starter-netflix-eureka-client
		

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

		
			org.springframework.boot
			spring-boot-starter-data-redis
		

		
			io.jsonwebtoken
			jjwt
			0.9.1
		
	


	
	
		
			
				org.springframework.cloud
				spring-cloud-dependencies
				Finchley.RELEASE
				pom
				import
			
		
	


	
		
			
				org.springframework.boot
				spring-boot-maven-plugin
			
		
	



以上便完成了代码部分。下面进行测试。测试工具postman。

1启动注册中心,认证服务,client-user。

1.获取token:在postman中输入http://localhost:6001/oauth/token?grant_type=password&username=admin&password=123456&scope=all

假设咱们在一个 web 端使用,grant_type 是 password,表明这是使用 OAuth2 的密码模式。

username=admin 和 password=123456 就相当于在 web 端登录界面输入的用户名和密码,我们在认证服务端配置中固定了用户名是 admin 、密码是 123456,而线上环境中则应该通过查询数据库获取。

scope=all 是权限有关的,在认证服务的 OAuthConfig 中指定了 scope 为 all 。

Authorization 要加在请求头中,格式为 Basic 空格 base64(clientId:clientSecret),这个微服务客户端的 client-id 是 user-client,client-secret 是 user-secret-8888,将这两个值通过冒号连接,并使用 base64 编码(user-client:user-secret-8888)之后的值为 dXNlci1jbGllbnQ6dXNlci1zZWNyZXQtODg4OA==,可以通过 https://www.sojson.com/base64.html 在线编码获取。

Spring Cloud系列 Spring Cloud OAuth2密码模式(resource owner password credentials)_第2张图片

 token返回到客户端。

2.通过token访问服务:我们在用户客户端中定义了一个接口 http://localhost:6101/client-user/get,现在就拿着上一步获取的 token 来请求这个接口。

同样需要请求头 Authorization,格式为 bearer + 空格 + token,正常情况下根据接口的逻辑,会把 token 原样返回

Spring Cloud系列 Spring Cloud OAuth2密码模式(resource owner password credentials)_第3张图片

3.刷新token: http://localhost:6001/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiJjNWMyYTdlMC1mYzc3LTRiN2ItYWE5Ni0wNzA5YmU5ZmZjZjQiLCJleHAiOjE1OTU2NDYwODgsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiZTYyMDgxNTctN2JkYy00MjBhLTkyMTctZTA0MDUzNzZjMDJhIiwiY2xpZW50X2lkIjoidXNlci1jbGllbnQifQ.gaNQF4UEjti_TZwJJaHAM8b7pd6JeeAysHre4jPbuxA

通过接口带着上一步获取的refresh_token.结果如下

Spring Cloud系列 Spring Cloud OAuth2密码模式(resource owner password credentials)_第4张图片 

你可能感兴趣的:(Spring Cloud系列 Spring Cloud OAuth2密码模式(resource owner password credentials))