博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring-Security-OAuth2遇到的奇怪问题
阅读量:6318 次
发布时间:2019-06-22

本文共 6818 字,大约阅读时间需要 22 分钟。

  hot3.png

以SpringFramework提供的sparklr2为蓝本,照葫芦画瓢画出一个OAuth2Server程序来,运行都没有问题。当正式要做项目的时候,却一而再再二三的出现怪异的问题。

一开始,是用户登录之后,直接报空指针错误。错误原因出现在AccessConfirmationController里,这是自己写的Controller,与Spring-Security-OAuth2配搭使用的,sparklr2里面有这个Controller。主要原因是getAccessConfirmation方法的参数model,里面没有给出名为“authorizationRequest”的对象,size为0.这个参数是从session里面取出来的,这个类在sparklr(包括葫芦画瓢的测试程序中是一样的)的代码如下:

import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.oauth2.provider.AuthorizationRequest;import org.springframework.security.oauth2.provider.ClientDetails;import org.springframework.security.oauth2.provider.ClientDetailsService;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.SessionAttributes;import org.springframework.web.servlet.ModelAndView;/** * Controller for retrieving the model for and displaying the confirmation page for access to a protected resource. *  * @author Ryan Heaton */@Controller@SessionAttributes("authorizationRequest")public class AccessConfirmationController {	private ClientDetailsService clientDetailsService;	@RequestMapping("/oauth/confirm_access")	public ModelAndView getAccessConfirmation(Map
model) throws Exception { AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest"); ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId()); model.put("auth_request", clientAuth); model.put("client", client); return new ModelAndView("access_confirmation", model); } @RequestMapping("/oauth/error") public String handleError(Map
model) throws Exception { // We can add more stuff to the model here for JSP rendering. If the client was a machine then // the JSON will already have been rendered. model.put("message", "There was a problem with the OAuth2 protocol"); return "oauth_error"; } @Autowired public void setClientDetailsService(ClientDetailsService clientDetailsService) { this.clientDetailsService = clientDetailsService; }}

里面声明了SessionAttributes,但方法的model里面没有。

我起初的解决方法是,将AuthorizationRequest对象添加到方法参数列表中来,用@ModelAttribute来加以修饰。果然,可以获得这个参数,也可以正常的获得accessToken了,然而通过该accessToken获取受保护的数据总是提示权限不够。

通过跟踪调查,发现Vote进行表决的时候,检查scope通不过。

客户应用提供了scope为ROLE_READ,但是提取的授权中,scope为“read+write”,本来应该为两个字符串的一个Set结果变成了只有一个字符串的Set,因此检查的时候总是通不过。

跟踪了好久,结果发现就是在AccessConfirmationController获取AuthorizationRequest对象的时候发生了问题:往session里面存的时候还是好的(AuthorizationEndpoint.authorize方法,第159行,通过往model里面put值完成设置到Session里面),scope属性为Set[read, write],但取出来就是Set[read+write]。

此时的代码如下:

import java.util.Enumeration;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.oauth2.provider.AuthorizationRequest;import org.springframework.security.oauth2.provider.ClientDetails;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.SessionAttributes;import org.springframework.web.servlet.ModelAndView;/** * Controller for retrieving the model for and displaying the confirmation page for access to a protected resource. *  * @author Ryan Heaton */@Controller@SessionAttributes("authorizationRequest")public class AccessConfirmationController {		private ClientDetailsService clientDetailsService;	@RequestMapping("/oauth/confirm_access")	public ModelAndView getAccessConfirmation(Map
model, @ModelAttribute("authorizationRequest")AuthorizationRequest clientAuth) throws Exception { model.remove("authorizationRequest"); ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId()); model.put("auth_request", clientAuth); model.put("client", client); return new ModelAndView("access_confirmation", model); } @RequestMapping("/oauth/error") public String handleError(Map
model) throws Exception { // We can add more stuff to the model here for JSP rendering. If the client was a machine then // the JSON will already have been rendered. model.put("message", "There was a problem with the OAuth2 protocol"); return "oauth2/error"; } @Autowired public void setClientDetailsService(ClientDetailsService clientDetailsService) { this.clientDetailsService = clientDetailsService; }}

后来不得已,将AuthorizationRequest对象从getAccessConfirmation的参数列表清除了出去,然后添加了HttpSession对象作为参数,然后从session中直接获取数据,结果就好了:scope=Set[read, write],这样后面的流程就都通了。

最后的代码为:

import java.util.Map;import javax.servlet.http.HttpSession;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.oauth2.provider.AuthorizationRequest;import org.springframework.security.oauth2.provider.ClientDetails;import org.springframework.security.oauth2.provider.ClientDetailsService;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.SessionAttributes;import org.springframework.web.servlet.ModelAndView;/** * Controller for retrieving the model for and displaying the confirmation page for access to a protected resource. *  * @author Ryan Heaton */@Controller@SessionAttributes("authorizationRequest")public class AccessConfirmationController {	private ClientDetailsService clientDetailsService;	@RequestMapping("/oauth/confirm_access")	public ModelAndView getAccessConfirmation(Map
model, HttpSession session) throws Exception { AuthorizationRequest clientAuth = (AuthorizationRequest) session.getAttribute("authorizationRequest");// session.removeAttribute("authorizationRequest");//不要删除,删除后面会报错。model里面删除不代表从Session中删除对象 ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId()); model.put("auth_request", clientAuth); model.put("client", client); return new ModelAndView("access_confirmation", model); } @RequestMapping("/oauth/error") public String handleError(Map
model) throws Exception { // We can add more stuff to the model here for JSP rendering. If the client was a machine then // the JSON will already have been rendered. model.put("message", "There was a problem with the OAuth2 protocol"); return "oauth_error"; } @Autowired public void setClientDetailsService(ClientDetailsService clientDetailsService) { this.clientDetailsService = clientDetailsService; }}

现在的问题是:

1.AccessConfirmationController的getAccessConfirmation为什么无法从model中获取AuthorizationRequest对象?如果将Session注入,是明明能看到里面有这个对象的。

2.将AuthorizationRequest声明在getAccessConfirmation方法中,然后用@ModelAttribute来修饰,为什么就能取出来了?但又为什么scope属性偏偏从Set[read, write]变成了Set[read+write]?谁搞的鬼?

3.在上述追踪过程中有没有遗漏什么地方,是导致这个问题的罪魁?

转载于:https://my.oschina.net/smzd/blog/111720

你可能感兴趣的文章
Office365 Exchange Hybrid 番外篇 ADFS后端SQL群集(一)
查看>>
lvs fullnat部署手册(三)rs内核加载toa篇
查看>>
SSL/TLS原理详解
查看>>
buildroot下查找外部编译器通过ext-toolchain-wrapper调用的参数
查看>>
iframe 在ie下面总是弹出新窗口解决方法
查看>>
android编译系统makefile(Android.mk)写法
查看>>
MD5源代码C++
查看>>
Eclipse 添加 Ibator
查看>>
Linux中变量$#,$@,$0,$1,$2,$*,$$,$?的含义
查看>>
Python编程语言
查看>>
十四、转到 linux
查看>>
Got error 241 'Invalid schema
查看>>
ReferenceError: event is not defined
查看>>
男人要内在美,更要外在美
查看>>
为什么要跟别人比?
查看>>
app启动白屏
查看>>
Oracle 提高查询性能(基础)
查看>>
学习知识应该像织网一样去学习——“网状学习法”
查看>>
Hadoop集群完全分布式安装
查看>>
QString,char,string之间赋值
查看>>