1. 首页
  2. >
  3. 编程技术
  4. >
  5. Java

SpringBoot2 整合 OAuth2 资源认证(保护)

接着上一篇:SpringBoot2 整合OAuth2实现统一认证

上一篇整合介绍了OAuth2的认证服务,接下来利用认证服务提供的token来包含我们的资源。

环境:2.2.11.RELEASE + OAuth2 + Redis

  • 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-data-redis</artifactId> 		</dependency> 		<dependency> 			<groupId>org.apache.commons</groupId> 			<artifactId>commons-pool2</artifactId> 		</dependency> 		<dependency> 			<groupId>org.springframework.security.oauth.boot</groupId> 			<artifactId>spring-security-oauth2-autoconfigure</artifactId> 			<version>2.2.11.RELEASE</version> 		</dependency>
  • application.yml
server:   port: 8088 --- spring:   application:     name: oauth-resource --- spring:   redis:     host: localhost     port: 6379     password:      database: 1     lettuce:       pool:         maxActive: 8         maxIdle: 100         minIdle: 10         maxWait: -1
  • Domain对象(我们在认证服务上是把Users对象序列化存储到了Redis,所以这里还需要这个类,其实如果用了网关,这些认证就不需要在资源端进行了)
public class Users implements UserDetails, Serializable {  	private static final long serialVersionUID = 1L;  	private String id ; 	private String username ; 	private String password ; }
  • 核心配置类
@Configuration @EnableResourceServer public class OAuthConfig extends ResourceServerConfigurerAdapter {    	private static final Logger logger = LoggerFactory.getLogger(OAuthConfig.class) ; 	 	public static final String RESOURCE_ID = "gx_resource_id";   	 	@Resource     private RedisConnectionFactory redisConnectionFactory ; 	     @Override       public void configure(ResourceServerSecurityConfigurer resources) throws Exception {           resources.resourceId(RESOURCE_ID) ;         OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();           oAuth2AuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());         resources.authenticationEntryPoint(oAuth2AuthenticationEntryPoint) ;         resources.tokenExtractor((request) -> {         	String tokenValue = extractToken(request) ;     		if (tokenValue != null) {     			PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(tokenValue, "");     			return authentication;     		}     		return null;         }) ;     }       private String extractToken(HttpServletRequest request) { 		// first check the header... Authorization: Bearer xxx 		String token = extractHeaderToken(request); 		// sencod check the header... access_token: xxx 		if (token == null) { 			token = request.getHeader("access_token") ; 		} 		// bearer type allows a request parameter as well 		if (token == null) { 			logger.debug("Token not found in headers. Trying request parameters.") ; 			token = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN) ; 			if (token == null) { 				logger.debug("Token not found in request parameters.  Not an OAuth2 request.") ; 			} else { 				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, OAuth2AccessToken.BEARER_TYPE); 			} 		} 		return token; 	}     private String extractHeaderToken(HttpServletRequest request) { 		Enumeration<String> headers = request.getHeaders("Authorization"); 		while (headers.hasMoreElements()) { // typically there is only one (most servers enforce that) 			String value = headers.nextElement(); 			if ((value.toLowerCase().startsWith(OAuth2AccessToken.BEARER_TYPE.toLowerCase()))) { 				String authHeaderValue = value.substring(OAuth2AccessToken.BEARER_TYPE.length()).trim(); 				// Add this here for the auth details later. Would be better to change the signature of this method. 				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, 						value.substring(0, OAuth2AccessToken.BEARER_TYPE.length()).trim()); 				int commaIndex = authHeaderValue.indexOf(','); 				if (commaIndex > 0) { 					authHeaderValue = authHeaderValue.substring(0, commaIndex); 				} 				return authHeaderValue; 			} 		} 		return null; 	}          @Override       public void configure(HttpSecurity http) throws Exception {       	http.csrf().disable() ;     	http.requestMatcher(request -> {     			String path = request.getServletPath() ;     			if (path != null && path.startsWith("/demo")) { 					return true ; 				}     			return false ;         	})     		.authorizeRequests()     		.anyRequest()     		.authenticated() ;     }          @Bean     public TokenStore tokenStore() {     	TokenStore tokenStore = null ;     	tokenStore = new RedisTokenStore(redisConnectionFactory) ;     	return tokenStore ;     }          @Bean       public WebResponseExceptionTranslator<?> webResponseExceptionTranslator() {           return new DefaultWebResponseExceptionTranslator() { 			@SuppressWarnings({ "unchecked", "rawtypes" }) 			@Override 			public ResponseEntity translate(Exception e) throws Exception { 				ResponseEntity<OAuth2Exception> responseEntity = super.translate(e) ; 				ResponseEntity<Map<String, Object>> customEntity = exceptionProcess(responseEntity); 				return customEntity ; 			}           };       }            private static ResponseEntity<Map<String, Object>> exceptionProcess( 			ResponseEntity<OAuth2Exception> responseEntity) { 		Map<String, Object> body = new HashMap<>() ; 		body.put("code", -1) ; 		OAuth2Exception excep = responseEntity.getBody() ; 		String errorMessage = excep.getMessage(); 		if (errorMessage != null) { 			errorMessage = "认证失败,非法用户" ; 			body.put("message", errorMessage) ; 		} else { 			String error = excep.getOAuth2ErrorCode(); 			if (error != null) { 				body.put("message", error) ; 			} else { 				body.put("message", "认证服务异常,未知错误") ; 			} 		} 		body.put("data", null) ; 		ResponseEntity<Map<String, Object>> customEntity = new ResponseEntity<>(body,  				responseEntity.getHeaders(), responseEntity.getStatusCode()) ; 		return customEntity; 	}   }  

核心配置类主要完整,开启资源服务认证,定义我们需要保护的接口,token的存储对象及错误信息的统一处理。

  • 测试接口
@RestController @RequestMapping("/demo") public class DemoController { 	 	@GetMapping("/res") 	public Object res() { 		return "success" ; 	} 	 } 

测试:

先直接访问token或者传一个错误的tokenj


SpringBoot2 整合 OAuth2 资源认证(保护)

接下先获取一个正确的token


SpringBoot2 整合 OAuth2 资源认证(保护)


SpringBoot2 整合 OAuth2 资源认证(保护)

成功了


完毕!!!