Oauth认证

最近做的系统需要用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&amp;x_controller=datacenter&amp;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() {

	}

}
 

猜你喜欢

转载自dsbjoe.iteye.com/blog/1158233