Spring Security Oauth2 授权服务开发之MongoDB

集成开发环境

·开发工具:Eclipse/Myeclipse/IntelliJ IDEA 任选其一

·运行环境:jdk1.7及以上版本

·数据库:MongoDB

spring-security-oauth2源码

·本地SVN地址:

svn://host /jd_product/fort/java_main/spring-cloud-base/dev/fort-spring-security-oauth2

·github地址:https://github.com/spring-projects/spring-security-oauth.git

构建授权服务

1、使用eclipse新建一个名称为“fort-auth”maven项目,将其pom.xml配置文件修改为如下:

<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 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.fort.jidisec</groupId>
	<artifactId>fort-auth</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>fort-auth Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.8.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-security</artifactId>
			<version>1.2.1.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>fort-spring-security-oauth2</groupId>
			<artifactId>fort-spring-security-oauth2</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-mongodb -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-mongodb</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.json/json -->
		<dependency>
			<groupId>org.json</groupId>
			<artifactId>json</artifactId>
			<version>20160810</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>fort-auth</finalName>
	</build>
</project>

 

2、新建程序启动类“Application.java”,如下所示:

@SpringBootApplication
@EnableAuthorizationServer
public class Application {

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

}

 

3、新建“AuthServerConfig.java”类继承“AuthorizationServerConfigurerAdapter”类初始化授权服务所需要的信息,如下所示:

@Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

	@Autowired
    private AuthenticationManager authenticationManager;
	
	@Autowired
	private ClientDetailsService mongoClientDetailsService;
	
	@Autowired
	private TokenStore mongoTokenStore;
	
	@Autowired
	private UserDetailsService mongoUserDetailsService;
	
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.withClientDetails(mongoClientDetailsService);
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.tokenStore(mongoTokenStore)
				 .authenticationManager(authenticationManager)
				 .userDetailsService(mongoUserDetailsService);
	}
	
}

 

4、新建“DataSourceConfig”类初始化数据源,如下所示:

@Configuration
public class DataSourceConfig {
	
	@Value("${spring.mongodb.uri}")
	private String mongoUri;
	
	@Value("${spring.mongodb.database}")
	private String mongoDatabase;
	
	@Bean("mongoDbFactory")
	public MongoDbFactory getMongoDbFactory() {
		return new SimpleMongoDbFactory(new MongoClient(new MongoClientURI(mongoUri)), mongoDatabase);
	}
	
	@Bean("mongoTemplate")
	@Resource(name="mongoDbFactory")
	public MongoTemplate getMongoTemplate(MongoDbFactory mongoDbFactory) {
		return new MongoTemplate(mongoDbFactory);
	}
}

5、新建“application.yml”配置文件,内容如下:

server:
  port: 8888

spring:
  mongodb:
    uri: mongodb://root:123@localhost:27017
    database: admin

5、定义查询认证信息的接口,代码如下:

@Service("mongoClientDetailsService")
public class MongoClientDetailsService extends MongoSuportTemplate implements ClientDetailsService {

	private final String CONLLECTION_NAME = "oauth_client_details";
	
	private PasswordEncoder passwordEncoder = NoOpPasswordEncoder.getInstance();
	
	public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
		BaseClientDetails client = mongoTemplate.findOne(new Query(Criteria.where("clientId").is(clientId)), BaseClientDetails.class, CONLLECTION_NAME);
		if(client != null) {
			String secret = client.getClientSecret();
			if(!(secret == null || "".equals(secret))) {
				client.setClientSecret(passwordEncoder.encode(secret));
			}
		}
		return client;
	}

	public void addClientDetails(ClientDetails clientDetails) {
		mongoTemplate.insert(clientDetails, CONLLECTION_NAME);
	}
	
	public void updateClientDetails(ClientDetails clientDetails) {
		Update update = new Update();
		update.set("resourceIds", clientDetails.getResourceIds());
		update.set("clientSecret", clientDetails.getClientSecret());
		update.set("authorizedGrantTypes", clientDetails.getAuthorizedGrantTypes());
		update.set("registeredRedirectUris", clientDetails.getRegisteredRedirectUri());
		update.set("authorities", clientDetails.getAuthorities());
		update.set("accessTokenValiditySeconds", clientDetails.getAccessTokenValiditySeconds());
		update.set("refreshTokenValiditySeconds", clientDetails.getRefreshTokenValiditySeconds());
		update.set("additionalInformation", clientDetails.getAdditionalInformation());
		update.set("scope", clientDetails.getScope());
		mongoTemplate.updateFirst(new Query(Criteria.where("clientId").is(clientDetails.getClientId())), update, CONLLECTION_NAME);
	}
	
	public void updateClientSecret(String clientId, String secret) {
		Update update = new Update();
		update.set("clientSecret", secret);
		mongoTemplate.updateFirst(new Query(Criteria.where("clientId").is(clientId)), update, CONLLECTION_NAME);
	}
	
	public void removeClientDetails(String clientId) {
		mongoTemplate.remove(new Query(Criteria.where("clientId").is(clientId)), CONLLECTION_NAME);
	}
	
	public List<ClientDetails> listClientDetails(){
		return mongoTemplate.findAll(ClientDetails.class, CONLLECTION_NAME);
	}
}
@Service("mongoTokenStore")
public class MongoTokenStore extends MongoSuportTemplate implements TokenStore {
	
	private final String TOKEN_CONLLECTION_NAME = "oauth_access_token";
	
	private final String TOKEN_REFRESH_CONLLECTION_NAME = "oauth_refresh_token";
	
	private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();

	public AuthenticationKeyGenerator getAuthenticationKeyGenerator() {
		return authenticationKeyGenerator;
	}

	public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) {
		this.authenticationKeyGenerator = authenticationKeyGenerator;
	}

	public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
		return readAuthentication(token.getValue());
	}

	public OAuth2Authentication readAuthentication(String token) {
		OAuth2Authentication authentication = null;
		OauthAccessToken oauthAccessToken = mongoTemplate.findOne(new Query(Criteria.where("token_id").is(extractTokenKey(token))), OauthAccessToken.class,TOKEN_CONLLECTION_NAME);
		if(oauthAccessToken != null) {
			authentication = deserializeAuthentication(oauthAccessToken.getAuthentication());
		}
		return authentication;
	}

	public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
		String refreshToken = null;
		if (token.getRefreshToken() != null) {
			refreshToken = token.getRefreshToken().getValue();
		}
		
		if (readAccessToken(token.getValue())!=null) {
			removeAccessToken(token.getValue());
		}
		
		OauthAccessToken oauthAccessToken = new OauthAccessToken();
		oauthAccessToken.setToken_id(extractTokenKey(token.getValue()));
		oauthAccessToken.setToken(serializeAccessToken(token));
		oauthAccessToken.setAuthentication_id(authenticationKeyGenerator.extractKey(authentication));
		oauthAccessToken.setUser_name(authentication.isClientOnly() ? null : authentication.getName());
		oauthAccessToken.setClient_id(authentication.getOAuth2Request().getClientId());
		oauthAccessToken.setAuthentication(serializeAuthentication(authentication));
		oauthAccessToken.setRefresh_token(extractTokenKey(refreshToken));
		
		mongoTemplate.insert(oauthAccessToken, TOKEN_CONLLECTION_NAME);
	}

	public OAuth2AccessToken readAccessToken(String tokenValue) {
		OAuth2AccessToken accessToken = null;
		OauthAccessToken oauthAccessToken = mongoTemplate.findOne(new Query(Criteria.where("token_id").is(extractTokenKey(tokenValue))), OauthAccessToken.class,TOKEN_CONLLECTION_NAME);
		if(oauthAccessToken != null) {
			accessToken = deserializeAccessToken(oauthAccessToken.getToken());
		}
		return accessToken;
	}

	public void removeAccessToken(OAuth2AccessToken token) {
		removeAccessToken(token.getValue());
	}
	
	public void removeAccessToken(String tokenValue) {
		mongoTemplate.remove(new Query(Criteria.where("token_id").is(extractTokenKey(tokenValue))), TOKEN_CONLLECTION_NAME);
	}

	public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
		OauthRefreshToken oauthRefreshToken = new OauthRefreshToken();
		oauthRefreshToken.setToken_id(extractTokenKey(refreshToken.getValue()));
		oauthRefreshToken.setToken(serializeRefreshToken(refreshToken));
		oauthRefreshToken.setAuthentication(serializeAuthentication(authentication));
		
		mongoTemplate.insert(oauthRefreshToken, TOKEN_REFRESH_CONLLECTION_NAME);
	}

	public OAuth2RefreshToken readRefreshToken(String tokenValue) {
		OAuth2RefreshToken refreshToken = null;
		OauthRefreshToken oauthRefreshToken = mongoTemplate.findOne(new Query(Criteria.where("token_id").is(extractTokenKey(tokenValue))), OauthRefreshToken.class, TOKEN_REFRESH_CONLLECTION_NAME);
		if(oauthRefreshToken != null) {
			refreshToken = deserializeRefreshToken(oauthRefreshToken.getToken());
		}
		return refreshToken;
	}

	public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
		return readAuthenticationForRefreshToken(token.getValue());
	}
	
	public OAuth2Authentication readAuthenticationForRefreshToken(String value) {
		OAuth2Authentication authentication = null;
		OauthRefreshToken oauthRefreshToken = mongoTemplate.findOne(new Query(Criteria.where("token_id").is(extractTokenKey(value))), OauthRefreshToken.class, TOKEN_REFRESH_CONLLECTION_NAME);
		if(oauthRefreshToken != null) {
			authentication = deserializeAuthentication(oauthRefreshToken.getAuthentication());
		}
		return authentication;
	}

	public void removeRefreshToken(OAuth2RefreshToken token) {
		removeRefreshToken(token.getValue());
	}

	public void removeRefreshToken(String token) {
		mongoTemplate.remove(new Query(Criteria.where("token_id").is(extractTokenKey(token))), TOKEN_REFRESH_CONLLECTION_NAME);
	}
	
	public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
		removeAccessTokenUsingRefreshToken(refreshToken.getValue());
	}
	
	public void removeAccessTokenUsingRefreshToken(String refreshToken) {
		mongoTemplate.remove(new Query(Criteria.where("refresh_token").is(extractTokenKey(refreshToken))), TOKEN_CONLLECTION_NAME);
	}

	public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
		String key = authenticationKeyGenerator.extractKey(authentication);
		OAuth2AccessToken accessToken = null;
		OauthAccessToken oauthAccessToken = mongoTemplate.findOne(new Query(Criteria.where("authentication_id").is(key)), OauthAccessToken.class, TOKEN_CONLLECTION_NAME);
		if(oauthAccessToken != null) {
			accessToken = deserializeAccessToken(oauthAccessToken.getToken());
		}
		return accessToken;
	}

	public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
		Query query = new Query();
		query.addCriteria(Criteria.where("client_id").is(clientId));
		query.addCriteria(Criteria.where("user_name"));
		List<OauthAccessToken> tokenList = mongoTemplate.findAllAndRemove(query, OauthAccessToken.class, TOKEN_CONLLECTION_NAME);

		Collection<OAuth2AccessToken> collection = new ArrayList<OAuth2AccessToken>();
		if(!(tokenList == null || tokenList.isEmpty())) {
			for(OauthAccessToken oauthAccessToken : tokenList) {
				collection.add(deserializeAccessToken(oauthAccessToken.getToken()));
			}
		}
		return collection;
	}

	public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("client_id").is(clientId));
		List<OauthAccessToken> tokenList = mongoTemplate.findAllAndRemove(query, OauthAccessToken.class, TOKEN_CONLLECTION_NAME);
		Collection<OAuth2AccessToken> collection = new ArrayList<OAuth2AccessToken>();
		if(!(tokenList == null || tokenList.isEmpty())) {
			for(OauthAccessToken oauthAccessToken : tokenList) {
				collection.add(deserializeAccessToken(oauthAccessToken.getToken()));
			}
		}
		return collection;
	}
	
	protected byte[] serializeAccessToken(OAuth2AccessToken token) {
		return SerializationUtils.serialize(token);
	}

	protected byte[] serializeRefreshToken(OAuth2RefreshToken token) {
		return SerializationUtils.serialize(token);
	}

	protected byte[] serializeAuthentication(OAuth2Authentication authentication) {
		return SerializationUtils.serialize(authentication);
	}

	protected OAuth2AccessToken deserializeAccessToken(byte[] token) {
		return SerializationUtils.deserialize(token);
	}

	protected OAuth2RefreshToken deserializeRefreshToken(byte[] token) {
		return SerializationUtils.deserialize(token);
	}

	protected OAuth2Authentication deserializeAuthentication(byte[] authentication) {
		return SerializationUtils.deserialize(authentication);
	}

	protected String extractTokenKey(String value) {
		if (value == null) {
			return null;
		}
		MessageDigest digest;
		try {
			digest = MessageDigest.getInstance("MD5");
		}
		catch (NoSuchAlgorithmException e) {
			throw new IllegalStateException("MD5 algorithm not available.  Fatal (should be in the JDK).");
		}

		try {
			byte[] bytes = digest.digest(value.getBytes("UTF-8"));
			return String.format("%032x", new BigInteger(1, bytes));
		}
		catch (UnsupportedEncodingException e) {
			throw new IllegalStateException("UTF-8 encoding not available.  Fatal (should be in the JDK).");
		}
	}
}
@Service("mongoUserDetailsService")
public class MongoUserDetailsService extends MongoSuportTemplate implements UserDetailsService {

	private final String USER_CONLLECTION = "user";
	
	@Autowired
	private RoleService roleService;
	
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		FortUserDetails user = mongoTemplate.findOne(new Query(Criteria.where("username").is(username)), FortUserDetails.class, USER_CONLLECTION);
		if(user == null) {
			throw new RuntimeException("查询用户信息时出现异常");
		}
		String roleType = user.getRoletype();
		if(roleType == null || "".equals(roleType)) {
			throw new RuntimeException("用户未分配权限");
		}
		Role role = roleService.findOneByRoleName(roleType);
		if(role == null) {
			throw new RuntimeException("用户未分配权限");
		}
		List<GrantedAuthority> roleList = new ArrayList<GrantedAuthority>();
		GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_USER");
		roleList.add(ga);
		user.setAuthorities(roleList);
		return user;
	}

}

 

数据库表结构

由于本示例需要将token以及client_id以及client_secret保存在数据库中,以便重启后还可再次使用,所以采用了MongoDB存储,有关数据结构信息请参考“JdbcTokenStore.java”和“JdbcClientDetailsService.java”

 

启动授权服务

启动授权服务是很简单的,您只需要运行“Application.java”即可启动授权服务。

测试授权服务

授权模式

oauth2规范中具备了四种授权模式,分别如下:

·授权码模式:authorization code

·简化模式:implicit

·密码模式:resource owner password credentials

·客户端模式:client credentials

注:本示例只演示密码模式和客户端模式,感兴趣的同学自己花时间测试另外两种授权模式。

获取token

密码模式

1、通过接口“/oauth/token”获取token信息,如下所示:

$ curl -d "username=user&password=123&grant_type=password&client_id=client&client_secret=secret&scope=app" http://198.9.9.21:8080/oauth/token

返回:

{"access_token":"8f9c7a5f-b0dd-48a3-a8d0-5969f172c15e","token_type":"bearer","refresh_token":"9fba821d-cbea-40c1-bb48-e173878eb6a1","expires_in":43088,"scope":"app"}

 

2、通过接口“/oauth/token”刷新token,如下所示:

$ curl -d "grant_type=refresh_token&client_id=client&client_secret=secret&refresh_token=9fba821d-cbea-40c1-bb48-e173878eb6a1" http://198.9.9.21:8080/oauth/token

返回:

{"access_token":"1092a1fe-5426-47bd-8091-bdff79039f30","token_type":"bearer","refresh_token":"9fba821d-cbea-40c1-bb48-e173878eb6a1","expires_in":43199,"scope":"app"}

 

客户端模式

1、通过接口“/oauth/token”获取token信息,如下所示:

$ curl -d "grant_type=client_credentials&client_id=client&client_secret=secret&scope=app" http://198.9.9.21:8080/oauth/token

返回:

{"access_token":"3e40b12a-ccdf-4c93-981b-8923a2d22358","token_type":"bearer","expires_in":43199,"scope":"app"}

校验token

密码模式

1、通过接口“/oauth/check_token”校验token信息,如下所示:

$ curl -d "token=1092a1fe-5426-47bd-8091-bdff79039f30" http://client:secret@198.9.9.21:8080/oauth/check_token

返回:

{"active":true,"exp":1510678642,"user_name":"user","authorities":["ROLE_USER","ROLE_API","ROLE_RESOURCE"],"client_id":"client","scope":["app"]}

客户端模式

curl -d "token=3e40b12a-ccdf-4c93-981b-8923a2d22358" http://client:secret@198.9.9.21:8080/oauth/check_token

返回:

{"scope":["app"],"active":true,"exp":1510678854,"client_id":"client"}

 

注:密码模式在校验token时会返回用户权限信息,客户端模式则没有权限信息返回,所以当用户权限信息归授权服务管辖时则采用密码模式,否则采用客户端授权模式。

构建资源服务

1、使用eclipse构建一个名称为“oauth2-resource”的maven项目,将其pom.xml配置文件修改为如下:

<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 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>oauth2-resource</groupId>

    <artifactId>oauth2-resource</artifactId>

    <packaging>war</packaging>

    <version>0.0.1-SNAPSHOT</version>

    <name>oauth2-resource Maven Webapp</name>

    <url>http://maven.apache.org</url>

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.5.6.RELEASE</version>

    </parent>

    <dependencies>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-security</artifactId>

            <version>1.2.1.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>fort-spring-security-oauth2</groupId>

            <artifactId>fort-spring-security-oauth2</artifactId>

            <version>0.0.1-SNAPSHOT</version>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

            <exclusions>

                <exclusion>

                    <groupId>org.springframework.boot</groupId>

                    <artifactId>spring-boot-starter-logging</artifactId>

                </exclusion>

            </exclusions>

        </dependency>

        <!-- Log4j -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-log4j2</artifactId>

        </dependency>

    </dependencies>

    <build>

        <finalName>oauth2-resource</finalName>

    </build>

</project>

2、新建程序启动类“Application.java”,如下所示:

@SpringBootApplication

@EnableResourceServer

public class Application {



    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }



}

3、新建“AuthResourceConfig.java”类继承“ResourceServerConfigurerAdapter”类初始化资源服务所需要的信息,如下所示:

@Configuration

public class AuthResourceConfig extends ResourceServerConfigurerAdapter {



    @Override

    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {

        RemoteTokenServices tokenService = new RemoteTokenServices();

        tokenService.setClientId("client");

        tokenService.setClientSecret("secret");

        tokenService.setCheckTokenEndpointUrl("http://198.9.9.21:8080/oauth/check_token");

        resources.tokenServices(tokenService);

    }



    @Override

    public void configure(HttpSecurity http) throws Exception {

        http

            .authorizeRequests().antMatchers("/private/data").hasRole("RESOURCE")

            .antMatchers("/api/data").permitAll();

    }

}

4、新建“ResourceController.java”类构建资源服务所提供的接口,分别为 “/private/data”和“/api/data”,如下所示:

@RestController

public class ResourceController {

   

    @RequestMapping("/private/data")

    public String getResource() {

        Object details = SecurityContextHolder.getContext().getAuthentication().getDetails();

        OAuth2AuthenticationDetails oAuth2Authen = (OAuth2AuthenticationDetails) details;

        System.out.println(oAuth2Authen.getTokenType());

        System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());

        return "Hello! This is private data.";

    }

   

    @RequestMapping("/api/data")

    public String getApiData() {

        Object details = SecurityContextHolder.getContext().getAuthentication().getDetails();

        if(details instanceof OAuth2AuthenticationDetails) {

            OAuth2AuthenticationDetails oAuth2Authen = (OAuth2AuthenticationDetails) details;

            System.out.println(oAuth2Authen.getTokenType());

            System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());

            return "Hello! This is api data.";

        }

        return "error";

    }

}

5、新建“application.yml”配置文件,内容如下:

server:
  port: 9001

启动资源服务

我们启动授权服务是通过运行“Application.java”来启动,同理也可以运行资源服务中的“Application.java”来启动资源服务。

资源服务接口权限测试

未授权访问接口

1、访问“/private/data”,如下所示:

$ curl http://198.9.9.21:9001/private/data

返回

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

2、访问“/api /data”,如下所示:

$ curl http://198.9.9.21:9001/api/data

返回

error

使用token访问接口

1、访问“/private/data”,如下所示:

·使用密码模式授权token访问

$ curl -d "usernaH "Authorization:Bearer 01a65ff5-cec7-4e2e-8812-69abac4ad566"  http://198.9.9.21:9001/private/data

返回

Hello! This is private data.

·使用客户端模式授权token访问

$ curl -H "Authorization:Bearer 3e40b12a-ccdf-4c93-981b-8923a2d22358"  http://198.9.9.21:9001/private/data

返回

{"error":"access_denied","error_description":"Access is denied"}

 

2、访问“/api /data”,如下所示:

$ curl -H "Authorization:Bearer 3e40b12a-ccdf-4c93-981b-8923a2d22358"  http://198.9.9.21:9001/api/data

返回

Hello! This is api data.

 

转载于:https://my.oschina.net/zhangzhigong/blog/1590493

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值