最近做的系统需要用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() {
}
}