`
rensanning
  • 浏览: 3514008 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
Efef1dba-f7dd-3931-8a61-8e1c76c3e39f
使用Titanium Mo...
浏览量:37479
Bbab2146-6e1d-3c50-acd6-c8bae29e307d
Cordova 3.x入门...
浏览量:604323
C08766e7-8a33-3f9b-9155-654af05c3484
常用Java开源Libra...
浏览量:678071
77063fb3-0ee7-3bfa-9c72-2a0234ebf83e
搭建 CentOS 6 服...
浏览量:87257
E40e5e76-1f3b-398e-b6a6-dc9cfbb38156
Spring Boot 入...
浏览量:399816
Abe39461-b089-344f-99fa-cdfbddea0e18
基于Spring Secu...
浏览量:69067
66a41a70-fdf0-3dc9-aa31-19b7e8b24672
MQTT入门
浏览量:90474
社区版块
存档分类
最新评论

Spring Security OAuth2 Provider 之 最小实现

阅读更多
不是客户端,而是服务端。

版本:
Spring Boot 1.4.3、Spring Security OAuth2 2.0.12

OAuth2.0的开源 Server / Client 实现可以参考这里:https://oauth.net/code/,这里采用Spring Security OAuth2实现四种授权模式中最常用的:Authorization Code Grant。


具体可以看OAuth2.0标准的定义:https://tools.ietf.org/html/rfc6749#section-4.1

这里首先只为演示 OAuth2.0 的整个过程,做最小实现!

Spring Security OAuth2默认提供的四个URL:
  • /oauth/authorize : 授权AuthorizationEndpoint
  • /oauth/token : 令牌TokenEndpoint
  • /oauth/check_token : 令牌校验CheckTokenEndpoint
  • /oauth/confirm_access : 授权页面WhitelabelApprovalEndpoint
  • /oauth/error : 错误页面WhitelabelErrorEndpoint

相关文章:
Spring Security OAuth2 Provider 之 最小实现
Spring Security OAuth2 Provider 之 数据库存储
Spring Security OAuth2 Provider 之 第三方登录简单演示
Spring Security OAuth2 Provider 之 自定义开发
Spring Security OAuth2 Provider 之 整合JWT

代码如下:

pom.xml
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
</dependency>


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


Config.java
public class Config {
	
	public static final String OAUTH_CLIENT_ID = "oauth_client";
	public static final String OAUTH_CLIENT_SECRET = "oauth_client_secret";
	public static final String RESOURCE_ID = "my_resource_id";
	public static final String[] SCOPES = { "read", "write" };

	@Configuration
	@EnableAuthorizationServer
	static class OAuthAuthorizationConfig extends AuthorizationServerConfigurerAdapter {
	    @Override
	    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
	        clients.inMemory()
	                .withClient(OAUTH_CLIENT_ID)
	                .secret(OAUTH_CLIENT_SECRET)
	                .resourceIds(RESOURCE_ID)
	                .scopes(SCOPES)
	                .authorities("ROLE_USER")
	                .authorizedGrantTypes("authorization_code", "refresh_token")
	                .redirectUris("http://default-oauth-callback.com")
	                .accessTokenValiditySeconds(60*30) // 30min
	                .refreshTokenValiditySeconds(60*60*24); // 24h
	    }
	}
	
	@Configuration
	@EnableResourceServer
	static class OAuthResourceConfig extends ResourceServerConfigurerAdapter {
		@Override
	    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
	        resources.resourceId(RESOURCE_ID);
	    }
		@Override
		public void configure(HttpSecurity http) throws Exception {
			http.authorizeRequests()
				.antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')")
	            .antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')");
		}
	}
	
	
	@Configuration
	@EnableWebSecurity
	static class SecurityConfig extends WebSecurityConfigurerAdapter {
	    @Override
	    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	        auth.inMemoryAuthentication()
	            .withUser("user").password("123").roles("USER")
	            .and()
	            .withUser("admin").password("123").roles("ADMIN");
	    }

	    @Override
	    protected void configure(HttpSecurity http) throws Exception {
	        http.csrf().disable();
        	http.authorizeRequests()
        		.antMatchers("/oauth/authorize").authenticated()
                .and()
                .httpBasic().realmName("OAuth Server");
	    }
	}

}


Controller.java
@RestController
public class Controller {

    @GetMapping("/api/get")
    public String get() {
        return "Hello World!";
    }

    @PostMapping("/api/post")
    public String post() {
    	return "POST process has finished.";
    }
    
    @GetMapping("/api/user")
    public Object get(HttpServletRequest req) {
    	SecurityContextImpl sci = (SecurityContextImpl) req.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
    	if (sci != null) {
    		Authentication authentication = sci.getAuthentication();
    		if (authentication != null) {
    			return authentication.getPrincipal();
    		}
    	}
        return "none";
    }
    
}


Test.java
public class Test {

	public static void main(String[] args) {
		System.out.println(generate("oauth_client", "oauth_client_secret"));
	}

	private static String generate(String clientId, String clientSecret) {
		String creds = String.format("%s:%s", new Object[] { clientId, clientSecret });
		try {
			return "Basic " + new String(Base64.encode(creds.getBytes("UTF-8")));
		} catch (UnsupportedEncodingException e) {
			throw new IllegalStateException("Could not convert String");
		}
	}

}


【Run As】【Spring Boot App】启动服务器后,看到以下Log:
引用
Mapped "{[/oauth/authorize]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
Mapped "{[/oauth/authorize],methods=[POST],params=[user_oauth_approval]}" onto public org.springframework.web.servlet.View org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.approveOrDeny(java.util.Map<java.lang.String, java.lang.String>,java.util.Map<java.lang.String, ?>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
Mapped "{[/oauth/token],methods=[POST]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
Mapped "{[/oauth/token],methods=[GET]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
Mapped "{[/oauth/check_token]}" onto public java.util.Map<java.lang.String, ?> org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.checkToken(java.lang.String)
Mapped "{[/oauth/confirm_access]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint.getAccessConfirmation(java.util.Map<java.lang.String, java.lang.Object>,javax.servlet.http.HttpServletRequest) throws java.lang.Exception
Mapped "{[/oauth/error]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint.handleError(javax.servlet.http.HttpServletRequest)


(1)授权请求(Get)

URL:http://localhost:8080/oauth/authorize?client_id=oauth_client&scope=read&response_type=code&state=rensanning&redirect_uri=http://default-oauth-callback.com

由于对/oauth/authorize开启了HTTP Basic认证,所以需要输入密码:

输入正确用户名密码(user/123)后显示授权页:


选择Approve点击Authorize按钮后,自动跳转到 http://default-oauth-callback.com?code=sdb6vF&state=rensanning


URL中的code参数值即为授权码,该值是一个6位英数字的随机数,具体可以看源码:org.springframework.security.oauth2.common.util.RandomValueStringGenerator.generate()

!!授权码10分钟过期目前还没有实现!! https://github.com/spring-projects/spring-security-oauth/issues/725

(2)获得令牌(Post)

URL:http://localhost:8080/oauth/token?grant_type=authorization_code&redirect_uri=http://default-oauth-callback.com&code=sdb6vF

【/oauth/token】默认采用的是HTTP Basic Auth(org.springframework.security.web.authentication.www.BasicAuthenticationFilter),所以需要在HTTP的header里提供clientId和clientSecret的Base64值。具体可以执行Test.java获取。
Authorization: Basic b2F1dGhfY2xpZW50Om9hdXRoX2NsaWVudF9zZWNyZXQ=


通过以下设置,可以通过参数的形式传递clientId和clientSecret的值。比如:http://localhost:8080/oauth/token?grant_type=authorization_code&redirect_uri=http://default-oauth-callback.com&code=sdb6vF&client_id=oauth_client&client_secret=oauth_client_secret
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
  @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.allowFormAuthenticationForClients();
  }
}


返回令牌信息
引用
{
    "access_token": "1cc5ffbd-faac-4d20-afd9-b8531acd248e",
    "token_type": "bearer",
    "refresh_token": "5b319fed-5600-4ea2-8c4f-61f6e3ea6e41",
    "expires_in": 1631,
    "scope": "read"
}

生成的令牌是一个UUID,具体可以看源码:org.springframework.security.oauth2.provider.token.DefaultTokenServices.createAccessToken()

(4)访问API(Get)

直接访问API返回401。URL:http://localhost:8080/api/get


通过access_token参数访问。URL:http://localhost:8080/api/get?access_token=1cc5ffbd-faac-4d20-afd9-b8531acd248e


通过http header参数访问。URL:http://localhost:8080/api/get
Authorization: Bearer 1cc5ffbd-faac-4d20-afd9-b8531acd248e


*** @EnableResourceServer 自动增加OAuth2AuthenticationProcessingFilter过滤器
*** !!SpringBoot1.5 @EnableResourceServer和@EnableWebSecurity配置的HttpSecurity有先后顺序的问题,需要特殊设置!!参考:
https://github.com/spring-projects/spring-security-oauth/issues/993#issuecomment-284430752
https://stackoverflow.com/questions/29893602/spring-security-form-logging-and-outh2-in-same-app

(5)刷新令牌(Post)

URL:http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=5b319fed-5600-4ea2-8c4f-61f6e3ea6e41
Authorization: Basic b2F1dGhfY2xpZW50Om9hdXRoX2NsaWVudF9zZWNyZXQ=

返回新的access_token:
引用
{
    "access_token": "3cbe70fc-753f-44ff-9bb4-0ba6bc3c9aab",
    "token_type": "bearer",
    "refresh_token": "5b319fed-5600-4ea2-8c4f-61f6e3ea6e41",
    "expires_in": 1800,
    "scope": "read"
}



旧的Token就不能再用了:


通过新的Token访问API:


同理,可以测试scope为write的权限!

参考:
http://projects.spring.io/spring-security-oauth/docs/oauth2.html
https://segmentfault.com/a/1190000010540911
http://ifeve.com/oauth2-tutorial-all/
http://websystique.com/spring-security/secure-spring-rest-api-using-oauth2/
http://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f
https://murashun.jp/blog/20150920-01.html
  • 大小: 5.1 KB
  • 大小: 7.2 KB
  • 大小: 8.4 KB
  • 大小: 85.3 KB
  • 大小: 72.1 KB
  • 大小: 69.8 KB
  • 大小: 73.4 KB
  • 大小: 82.8 KB
  • 大小: 75.7 KB
  • 大小: 70.5 KB
  • 大小: 136.8 KB
1
0
分享到:
评论
1 楼 海纳百川4277 2017-12-11  
日子里面有异常信息 怎么解决的?

相关推荐

    Spring Security OAuth2 Provider 之 第三方登录简单演示

    NULL 博文链接:https://rensanning.iteye.com/blog/2386309

    oauth2-family-barrel:OAuth2全家桶项目。本项目演示了如何使用spring-boot,spring-security以及spring-security-oauth快速构建OAuth2服务框架体系

    oauth2-family-barrel OAuth2全家桶 什么是oauth2-family-barrel oauth2-family-barrel项目,即OAuth2全家桶项目。 本项演示了如何使用 以及 快速整合一套基于OAuth2协议的鉴权,授权服务中心,客户端以及遵循...

    授权服务器:Spring Boot OAuth 2.0和OpenID Connect身份提供者授权服务器

    授权服务器兼容OAuth 2.0和OpenID Connect(OIDC)的授权服务器,仅用于演示目的,可用作OAuth2 / OIDC研讨会的一部分。目标此授权服务器应... 作为开源免费提供支持学习OAuth2 / OpenID Connect的努力(自学或作为...

    xmljava系统源码-simple-oauth2:一个简单oauth2应用服务,为第三方应用提供用户登录和授权

    这是一个简单的OAuth2.0的服务器,实现了OAuth 2.0的四种通用授权方式,可以用于应用的统一单点登录、权限控制。 项目提供了相应的客户端、web filter、网关组件,实现应用的分布式和集中式权限控制,并给出各种场景...

    cxf+spring webservice jar包

    oauth-provider-20100527.jar opensaml-2.5.1-1.jar openws-1.4.2-1.jar relaxngDatatype-20020414.jar saaj-api-1.3.4.jar saaj-impl-1.3.19.jar serializer-2.7.1.jar slf4j-api-1.6.2.jar slf4j-jdk14-1.6.2.jar ...

    play-framework-reactivemongo-oauth2.0:这是示例应用程序,我们在其中使用了 Play-Framework 2.3.x、Scala 2.11.x、ReactiveMongo-Extensions、Cake-Patter 和 Scala Oauth 2.0

    使用 Play-Framework 2.3.x 的 Scala Oauth 2.0 在这个示例应用程序中,我们使用Oauth2.0创建带有Play-Framework 2.3.x 、 ReactiveMongo-Extensions 、 Cake-Pattern和Scala-Oauth2-Provider 的API。 我们使用 ...

    cxf(jax-ws)+spring+hibernate整合包

    1.1.jar,log4j-1.2.14.jar,mina-core-2.0.7.jar,mssqlserver2.jar,msv-core-2011.1.jar,neethi-3.0.2.jar,oauth-20100527.jar,oauth-provider-20100527.jar,opensaml-2.5.1-1.jar,openws-1.4.2-1.jar,...

    java开源包2

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包3

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包4

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包1

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包11

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包6

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包5

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包10

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包8

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包7

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包9

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    java开源包101

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

    Java资源包01

    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

Global site tag (gtag.js) - Google Analytics