最近做的系统需要用oauth作权限管理,总结起来还是挺简单的。
关于oauth可以参考这个教程:基于 OAuth 安全协议的 Java 应用编程
由于Oauth协议通信需要传递很多参数,可以自己整合,这里用的是oauth-signpost,可以从oauth-signpos查看相关API
整个流程大概就是:
应用(consumer)向应用服务商,也叫provider(新浪、搜狐等微博)请求request_token。 得到request_token后重定向用户到服务商的授权页面。 如果用户选择授权你得应用,用request_token向服务商请求换取access_token。 得到access_token等信息访问受限资源。
<bean id="provider" class="oauth.signpost.basic.DefaultOAuthProvider"> <constructor-arg index="0"> <!-- oauth 服务器的requestToken请求地址--> <value>http://xxx.xxx/OAuth/RequestToken</value> </constructor-arg> <constructor-arg index="1"> <!-- oauth 服务器的AcessToken请求地址--> <value>http://xxx.xxx//OAuth/GetAccessToken</value> </constructor-arg> <constructor-arg index="2"> <!-- oauth 服务器的用户授权页面请求地址--> <value>http://xxx.xxx//OAuth/AuthorizeToken</value> </constructor-arg> </bean> <!-- oauth 这里就是oauth服务器提供的接口url,这里的例子是请求用户的基本信息,服务器会以json的格式返回结果--> <bean id="protectedResourceUrl" class="java.lang.String" > <constructor-arg> <value>http://xxx.xxx/admin/acl/index?x_module=datacenter&x_controller=datacenter&x_action=datacenter</value> </constructor-arg> </bean> <!-- consumer,也就是第三方应用,构造函数需要的是由oauth服务器提供的CONSUMER_KEY 和 CONSUMER_SECRET --> <bean id="consumer" class="oauth.signpost.basic.DefaultOAuthConsumer"> <constructor-arg index="0"> <value>LOGIN-KEY</value> </constructor-arg> <constructor-arg index="1"> <value>LOGIN-SECRET</value> </constructor-arg> </bean>
provider和consumer都已经初始化完毕,下面就可以开始进行oauth认证,我这边做了一个过滤器,拦截所有请求。
public class OauthFilter implements Filter { private String IS_USER_AUTHORISED = "is_user_authorised"; private String USER_NAME = "oauth_user_name"; private String FORBIDDEN_PAGE = "403.jsp"; private OAuthProvider provider; private OAuthConsumer consumer; private String protectedResourceUrl; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest)request; ServletContext context = req.getSession().getServletContext(); String uri = req.getRequestURI(); if(uri.endsWith(FORBIDDEN_PAGE)){ chain.doFilter(request, response); return; } //从session查看是否已经授权,是的话直接无视跳转 HttpSession session = req.getSession(); Boolean isAuthorized = (Boolean)session.getAttribute(IS_USER_AUTHORISED); if(isAuthorized != null && Boolean.TRUE.equals(isAuthorized)){ chain.doFilter(request, response); return; } if(provider == null || consumer == null){ ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context); provider = (OAuthProvider)ctx.getBean("provider"); consumer = (OAuthConsumer)ctx.getBean("consumer"); protectedResourceUrl = (String)ctx.getBean("protectedResourceUrl"); } try { String verifier = request.getParameter("oauth_verifier"); //oauth_verifier不为空说明已经获得了用户授权,带着用户和verifier去cas获取AccessToken if(verifier != null){ //重要,如果是用的1.0a协议,必须设置为true,否则报401错误 provider.setOAuth10a(true); //带着verifier去cas获取AccessToken provider.retrieveAccessToken(consumer, verifier); //获取到了AccessToken,下面就是请求受保护的资源 String result = getFromCAS(protectedResourceUrl); //获得系统给的json返回值后,解析 //样例:{"status":0,"data":{"has_permission":true,"app_permission":"880001","user_permissions":["880001"]}} //这里只要关注has_permission是不是为true就可以了 JSONObject jsonObject = JSONObject.fromObject(result); jsonObject = JSONObject.fromObject(jsonObject.get("data")); if(Boolean.TRUE.equals(jsonObject.get("has_permission"))){ session.setAttribute(IS_USER_AUTHORISED, true); //获取登陆玩家的信息,这里只需要fullName,用于显示在数据中心 String userInfo = getFromCAS("http://admin.platform.trac.cn/admin/acl/loggedInUser"); jsonObject = JSONObject.fromObject(userInfo); jsonObject = JSONObject.fromObject(jsonObject.get("data")); session.setAttribute(USER_NAME, jsonObject.get("fullname")); chain.doFilter(request, response); return ; }else{ String forbiddenPage = req.getContextPath()+"/"+FORBIDDEN_PAGE; ((HttpServletResponse)response).sendRedirect(forbiddenPage); } }else{ String url = provider.retrieveRequestToken(consumer, req.getRequestURL().toString()); ((HttpServletResponse)response).sendRedirect(url); } } catch (OAuthMessageSignerException e) { e.printStackTrace(); } catch (OAuthNotAuthorizedException e) { e.printStackTrace(); } catch (OAuthExpectationFailedException e) { e.printStackTrace(); } catch (OAuthCommunicationException e) { e.printStackTrace(); } } private String getFromCAS(String urlString) throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, IOException{ URL url = new URL(urlString); HttpURLConnection userRequest = (HttpURLConnection) url.openConnection(); userRequest.setDoOutput(true); consumer.sign(userRequest); userRequest.connect(); BufferedReader in = new BufferedReader(new InputStreamReader(userRequest .getInputStream())); String inputLine; StringBuffer result = new StringBuffer(); while ((inputLine = in.readLine()) != null) { System.out.println(inputLine); result.append(inputLine); } return result.toString(); } @Override public void destroy() { } }