用Filter实现GAE上的User Authentication

编者按:好吧,就是spring security的雏形概念。

Google App Engine 提供了非常详细的User Authentication的方法,详情参见Users Java API 概述。主要包括了两种方法:

在 Java 中使用用户身份验证
如果你只有单个servlet,那么很简单,在逻辑处理前调用Google提供的API(UserService)判断当前用户登录情况就可以了。

import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
UserService userService = UserServiceFactory.getUserService();
String thisURL = request.getRequestURI();
if (request.getUserPrincipal() != null) {
response.getWriter().println(“<p>Hello, ” +
request.getUserPrincipal().getName() +
“! You can <a href=\”” +
userService.createLogoutURL(thisURL) +
“\”>sign out</a>.</p>”);
} else {
response.getWriter().println(“<p>Please <a href=\”” +
userService.createLoginURL(thisURL) +
“\”>sign in</a>.</p>”);
}
}
}

使用 web.xml 强制登录和管理访问
如果你的应用比较复杂,不止一个servlet,Google App Engine支持标准部署描述符web.xml中的安全约束,但是不支持自定义角色,只支持login和admin两种权限。具体示例如下

<security-constraint>
<web-resource-collection>
<url-pattern>/profile/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>

另外也可以通过google自己的部署描述符app.yaml来编写。需要注意的是App在Deploy的时候,如果应用中有app.yaml,则SDK会按照它的内容重新生成web.xml和appengine-web.xml并覆盖原来的文件。所以如果你要启用app.yaml,你需要把web.xml和appengine-web.xml中所有的内容按照YAML文件的格式全部写到app.yaml里面去。具体示例如下:

handlers:
- url: /profile/*
login: required
- url: /admin/*
servlet: com.example.AdminServlet
login: admin

编者按:需要吐槽的是app.yaml并不完全支持web.xml,至少我没有找到如何配置load-on-startup=1怎么写,所以我个人不推荐这种用法。
编者又按:app.yaml的支持功能比web.xml+appengine-web.xml还要多,所以如果你不巧正好遇到,还是得听Google的话用app.yaml.
编者最后按:我的应用比较复杂,所以Java中写code的办法没法适用,但是很努力尝试第二种方法均告失败,不管是web.xml还是app.yaml都不成功。这才总结出了上述的一些经验,以及遇到了下面两种都没有找到解法的问题。

  • 登录之后仍然显示Your client does not have permission to get URL
  • Error: User not in required role

以上两个问题均没有比较明确的解法,所以才有了本文的内容。


用Filter实现User Authentication
主要借鉴了Spring Security的思想(明明是写完才发现的。。。),然后借用了第一种方法中的code。具体的方法说起来很简单,就是在需要做权限判断的URL前添加Filter,如果权限判断失败,则跳转到Google Login的URL。先看一下实现的代码。
UserFilter.java中的实现。

@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filter)
throws IOException, ServletException {
log.info(“———–UserFilter doFilter Begin————”);
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String thisURL = request.getRequestURI();
if (request.getUserPrincipal() == null
|| (!userService.isUserLoggedIn())) {
response.setContentType(“text/html”);
response.sendRedirect(userService.createLoginURL(thisURL));
} else {
log.info(userService.getCurrentUser().getEmail());
filter.doFilter(servletRequest, servletResponse);
}
}

web.xml中相应的配置。

<filter>
<filter-name>userFilter</filter-name>
<filter-class>com.pamirhostel.booking.filters.UserFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>userFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>

说穿了很简单,但是基于GAE的实现略有不同,总结下来的几点经验。

  • URL最好按照功能划分子目录。例如“/cron/*”是用来实现cron job的。由于GAE的backend,cron job, task queue都是通过调用URL来实现的,所以之前喜欢把所有URI都放在Root下的习惯在这里就不适用了。
  • Filter默认不是HTTP的,所以调用request,response前需要下溯造型成HTTPRequest.
  • request.getUserPrincipal只能用来判断是否当前有Google帐号登录,这是有逻辑漏洞的。例如我的应用是For Google Apps的,所以即使当前用户登录了它自己的Google Account也是没用的。所以需要添加进一步的判断userService.isUserLoggedIn。
  • 如果多组功能需要进行用户验证,直接多添加几个filter-mapping就好了。

目前该Filter很好用,还没有什么further question,有什么问题留下评论一起讨论把。

 

用Google Custom Engine替代WordPress默认搜索

创建自己的Google Custom Engine

Step 1

访问http://www.google.com/coop/cse/?hl=zh-CN,选择”创建自定义搜索“.

Step 2

按照提示定义自己的搜索引擎语言和网站范围.由于主要使用自己Blog的搜索,所以我选择的是”仅我选择的网站“.然后在”要搜索的网站“中填入自己网站的地址.

Step 3

完成创建后就可以在”我创建的搜索引擎“中看到你刚才创建的自定义搜索了.点击”控制面板“进行下一步的配置.

Step 4

选择”编制索引“,将你网站的sitemap导入你的自定义搜索,编制索引可能需要花一些时间,所以一开始你的搜索是不会有任何结果的.

Step 5

选择”代码“,点击”在您的网站上托管搜索结果“,”iframe“.获得”搜索框代码“和”搜索结果代码“.

这样,你的自定义搜索就算创建完成了.你还可以通过”优化”,”外观”来完善你的自定义搜索.

修改Wordpress默认搜索

主要修改的就是你当前theme中的searchform.php和search.php.你可以手动修改也可以通过Appearance->Editor来修改.

Step 1 修改searchform.php.

这是我修改后的searchform.php.

<form method=”get” id=”cse-search-box” action=”<?php bloginfo(‘url’); ?>/”>
<label class=”hidden” for=”s”><?php _e(‘Search for:’); ?></label>
<div><input type=”text” value=”<?php the_search_query(); ?>” name=”q” id=”q” size=”31″ />
<input type=”submit” id=”searchsubmit” value=”Search” />
<input type=”hidden” name=”cx” value=”xxxxxxxxxxxxxxxxxxxxxxxxxxxx” />
<input type=”hidden” name=”cof” value=”FORID:xx” />
<input type=”hidden” name=”ie” value=”UTF-8″ />
<input type=”hidden” name=”s” value=”Search”/>
<input type=”hidden” name=submit” value=””/>

</div>
</form>

请注意黑色的修改部分,具体的修改根据theme也会略有不同。主要都是根据”搜索框代码“进行的修改。比较注意的是需要增加”s=Search”,”submit=”这两个hidden,这是为了让wordpress能够跳转到search.php.

Step 2 修改search.php.

我选择的是两栏式的Theme,然后希望搜索结果显示在页面的左中,所以将search.php修改成如下格式.

<?php get_header(); ?>
<div id=”main”>
<div id=”content” class=”narrowcolumn”>
<!–               Google Search Result Code                    –>
<!–               Google Search Result Code                    –>
</div>
<?php get_sidebar(); ?>
</div>
<?php get_footer(); ?>

将之前获得的”搜索结果代码“贴在指定的地方就可以了。如果你不想要sidebar,也可以在这个基础上作自己的修改。

Tip 1:

貌似http://www.google.com/coop/cse/http://www.google.com/coop/cse/?hl=zh-CN的数据同步有一些问题.一开始在英文版下注册的Custom Engine在中文版里面看不到.考虑到最后需要中文效果,所以我还是选择在后者创建自己的搜索引擎.

Tip 2:

我的”搜索框代码”不知道为什么缺少下面这段JS调用,一开始尝试了半天也没有办法起作用.创建其他新的自定义搜索就没有问题,真实奇怪.Anyway,如果你的搜索框无法正常跳转,看看是不是这个问题.

<script type=”text/javascript” src=”http://www.google.com/coop/cse/brand?form=cse-search-box&lang=zh-Hans”></script>

Tip 3:

通过”控制面板“->”赚钱“.你可以通过到你的Adsense帐户创建”搜索广告”,在你搜索结果页中显示Google Adsense广告,赚点小钱.

具体就不细说了,有问题可以联系我.

 

无觅相关文章插件,快速提升流量