spring oauth2.0 demo入门分析

这里不对如何实现oauth2.0分析,也不对security做分析,读者可以google下security相关的知识,这里主要列出看oauth2.0demo时流程流转存在的疑惑。

1.oauth 2.0中的四个角色,资源拥有者,资源服务器,授权服务器,客户端。

2.spring security限制访问受限资源

3.client请求资源过程流转分析

1.oauth 2.0中的四个角色不再接受,不明白的可以google下,如果有充足的实际可以看下oauth 2.0完整译文或者原文。如果时间紧可以通过互联网对oauth2.0做初步的了解。

 

2.spring security限制资源访问

oauth2.0主要解决三方客户端访问资源需要的资源凭证的安全性,那么这里势必会牵涉到资源访问保护。spring oauth在spring security的基础上实现的,所以需要对spring security有一点的了解。
tonr spring security配置


		
		
		

		
		
		
		
	

上面主要表达的是对于http://localhost/sparklr/xxx这类的链接需要验证,采用的是form验证,登陆的url在form-login配置片段里给出,登陆后以客户端的身份访问资源服务器的资源。

sparklr spring security配置片段


		
		
		
		
		
		
		
	

上面主要是表达的是对photos资源的访问需要时授权的用户。

接下来我们来看看整个流程是怎么样的。

3.client请求资源流程

a.  用户通过浏览器访问http://localhost/tonr/,用户点击sparklr pics
b. 请求被spring给拦截,要求做登陆进行权限校验(tonr站点的验证)
c. 若登陆成功,我们点击sparklr pics访问的url是sparklr/photos所以会被tonr的SparklrController处理

@RequestMapping("/sparklr/photos")
	public String photos(Model model) throws Exception {
		model.addAttribute("photoIds", sparklrService.getSparklrPhotoIds());
		return "sparklr";
	}

上面这两句话很重要,

sparklrService.getSparklrPhotoIds()

该方法访问资源服务器的资源,资源服务器会对进行权限验证,这也是oauth协议工作的地方,我们先看是如何跳转到sparklr服务器的

public List getSparklrPhotoIds() throws SparklrException {
		try {
			InputStream photosXML = new ByteArrayInputStream(
					sparklrRestTemplate.getForObject(
							URI.create(sparklrPhotoListURL), byte[].class));
			System.out.println("hiiii, i have get the photo info");

			final List photoIds = new ArrayList();
			SAXParserFactory parserFactory = SAXParserFactory.newInstance();
			parserFactory.setValidating(false);
			parserFactory.setXIncludeAware(false);
			parserFactory.setNamespaceAware(false);
			SAXParser parser = parserFactory.newSAXParser();
			parser.parse(photosXML, new DefaultHandler() {
				@Override
				public void startElement(String uri, String localName,
						String qName, Attributes attributes)
						throws SAXException {
					if ("photo".equals(qName)) {
						photoIds.add(attributes.getValue("id"));
					}
				}
			});
			return photoIds;
		} catch (IOException e) {
			throw new IllegalStateException(e);
		} catch (SAXException e) {
			throw new IllegalStateException(e);
		} catch (ParserConfigurationException e) {
			throw new IllegalStateException(e);
		}
	}

如果不留意可能还奇怪怎么会跳转到资源服务器进行验证了呢?

InputStream photosXML = new ByteArrayInputStream(
					sparklrRestTemplate.getForObject(
							URI.create(sparklrPhotoListURL), byte[].class));

注意到了没 URI.create(spaklrPhotoLISTURL)这里,请求资源服务器的资源,上面的配置我们看到,资源服务器会对请求校验。这里或许会有人对这个url怎么来的有些疑惑

sparklrPhotoListURL

其实在resources目录下有sparklr.properties配置文件,该文件最后被spring处理,绑定到这个ServiceBean里(spring-servlet.xml里有引用这个配置文件,看下就明白了),

spring会对该配置文件解析,然后将spring-servlet.xml里的占位符的地方给替换成具体的配置文件里的值。ok继续Controller往下走,最后一句不是么

return "sparklr";

先别急,资源服务器验证还没走完呢。我们明白了访问图片的时候客户端像服务器端发送http://localhost:8080/sparklr2/photos?format=xml,由于资源服务器(同时也是授权服务器)对这类请求要求权限验证,上面的配置文件说过了。所以tonr客户端会引导用户到资源服务器/授权服务器进行授权;这里表达不够清晰或者是不正确,应该是读取受限资源,tonr发起授权请求(如何处理这个异常就是spring oauth处理了)

tonr2 18:08:45.233 [DEBUG] DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/sparklr2/oauth/authorize?client_id=tonr&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Ftonr%2Fsparklr%2Fphotos&response_type=code&scope=read+write&state=iVZRRl'

请求被导向了资源服务器登录页面(如果你还是不够明白,你可以想象你用新浪微博登陆某个小网站,如果你新浪微博登陆过期了, 新浪微博会要你登陆一次),登陆成功后会有一个页面让资源拥有者(用户)确认是否允许tonr访问资源,注意浏览器的url:http://localhost:8080/sparklr2/oauth/authorize?client_id=tonr&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Ftonr%2Fsparklr%2Fphotos&response_type=code&scope=read+write&state=EGwPYB(这个过程可以用chrome的开发者工具查看,结合后台log)

根据oauth2.0规范,client_id redirect_url response_type code 都是必须的,如果允许后,tonr能从授权服务器拿到一个access_token(这个过程是一个复杂的交互过程,可以写一系列的文章了,先把它当做黑盒,不影响我们分析),以后客户端拿着这个access_token去获取资源,资源服务器会检查token的有效性。到这里我们可以继续往下走了,拿到这个access_token后资源服务器会根据redirect_uri重定向到这个地址,用户在三方客户端上进行资源访问了。

我们sparklr.jsp视图(WEB-INF/jsp下),注意这个视图文件里的代码片段

  • "/>
 
  • "/>
  • 这里具体的图片,查看SparklrController

    @RequestMapping("/sparklr/photos/{id}")
    	public ResponseEntity photo(@PathVariable String id) throws Exception {
    		InputStream photo = sparklrService.loadSparklrPhoto(id);
    		if (photo == null) {
    			throw new UnavailableException("The requested photo does not exist");
    		}
    		BufferedImage body;
    		MediaType contentType = MediaType.IMAGE_JPEG;
    		Iterator imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
    		if (imageReaders.hasNext()) {
    			ImageReader imageReader = imageReaders.next();
    			ImageReadParam irp = imageReader.getDefaultReadParam();
    			imageReader.setInput(new MemoryCacheImageInputStream(photo), true);
    			body = imageReader.read(0, irp);
    		} else {
    			throw new HttpMessageNotReadableException("Could not find javax.imageio.ImageReader for Content-Type ["
    					+ contentType + "]");
    		}
    		HttpHeaders headers = new HttpHeaders();
    		headers.setContentType(MediaType.IMAGE_JPEG);
    		return new ResponseEntity(body, headers, HttpStatus.OK);
    	}

    这里的分析跟获取图片所有数据类似,输入流的获取从配置文件里读取到的资源服务器的url,然后进行读

    public InputStream loadSparklrPhoto(String id) throws SparklrException {
    		return new ByteArrayInputStream(sparklrRestTemplate.getForObject(
    				URI.create(String.format(sparklrPhotoURLPattern, id)),
    				byte[].class));
    	}

    再然后将图片数据返回给浏览器,显示之。

    这里省略了很多很多实现,只是对demo的流程进行了简易的分析。行文里如果有错误,欢迎大家批评指正。

     原文地址:http://marspring.mobi/spring-oauth2-0-demo/

     

    你可能感兴趣的:(spring)