安全是每一个web程序必须考虑的问题,安全很重要的一部分就是身份验证。我们可以将身份验证写成一个类,然后在每个功能模块实现的时候调用,但是即使你只须一句代码调用身份验证,当你的项目有几百个功能模块的时候,这也是一个不小的工作,说不定有时候还会忘记。
Filter 技术是 servlet 2.3 新增加的功能,它使用户可以改变一个request 和修改一个 response. Filter 不是一个 servlet, 它不能产生一个 response, 它能够在一个 request 到达 servlet 之前预处理 request, 也可以在离开 servlet 时处理 response. 换种说法 ,filter 其实是一个 ”servlet chaining”(servlet 链 ). 一个 filter 包括 :
1. 在 servlet 被调用之前截获 ;
2. 在 servlet 被调用之前检查 servlet request;
3. 根据需要修改 request 头和 request 数据 ;
4. 根据需要修改 response 头和 response 数据 ;
5. 在 servlet 被调用之后截获 .
具体的在这里不多介绍。用Filter可以做到很多事情,比如常用的SetCharacterEncodingFilter可以统一解决编码问题。总之那些可以统一进行的“预处理”工作就可以用Filter来做。如果我们用Filter来进行统一的身份验证,那样在功能模块代码中就不用管什么权限了。
大致思路是:定义访问URI及其所需权限,在会话中存储用户所具有的权限,每次访问的时候 根据URI找到所需的权限,然后检查用户是不是满足所有权限要求。如果满足,放行(chain.doFilter(request, response);),如果不满足,拦截(response.sendError(404);)。
实现
AccessIdentity.java
Access.java URI-权限类
AccessAnalyst.java 权限分析
过滤器
Filter 技术是 servlet 2.3 新增加的功能,它使用户可以改变一个request 和修改一个 response. Filter 不是一个 servlet, 它不能产生一个 response, 它能够在一个 request 到达 servlet 之前预处理 request, 也可以在离开 servlet 时处理 response. 换种说法 ,filter 其实是一个 ”servlet chaining”(servlet 链 ). 一个 filter 包括 :
1. 在 servlet 被调用之前截获 ;
2. 在 servlet 被调用之前检查 servlet request;
3. 根据需要修改 request 头和 request 数据 ;
4. 根据需要修改 response 头和 response 数据 ;
5. 在 servlet 被调用之后截获 .
具体的在这里不多介绍。用Filter可以做到很多事情,比如常用的SetCharacterEncodingFilter可以统一解决编码问题。总之那些可以统一进行的“预处理”工作就可以用Filter来做。如果我们用Filter来进行统一的身份验证,那样在功能模块代码中就不用管什么权限了。
大致思路是:定义访问URI及其所需权限,在会话中存储用户所具有的权限,每次访问的时候 根据URI找到所需的权限,然后检查用户是不是满足所有权限要求。如果满足,放行(chain.doFilter(request, response);),如果不满足,拦截(response.sendError(404);)。
实现
AccessIdentity.java
/**
* 用户身份权限类
*
* @author wenjianwzz
*
*/
public class AccessIdentity {
UserEntity user;
Date login;
Date lastActive;
Date createTime;
String ip;
List<String> tips = new ArrayList<String>();
HashMap<String, Boolean> privilege;
HashMap<String, Object> attribute = new HashMap<String, Object>();
public AccessIdentity(String ip) {
lastActive = createTime = new Date();
this.ip = ip;
refreshPrivilege();
}
private void refreshPrivilege() {
if (privilege == null) {
privilege = new HashMap<String, Boolean>();
}
privilege.clear();
privilege.put("public", true);
if (user != null) {
privilege.put("login", true);
List<String> p = user.getPrivilege();
if (p != null)
for (int i = 0; i < p.size(); i++) {
privilege.put(p.get(i), true);
}
}
}
public void notifyActive() {
lastActive = new Date();
}
public void notifyLogout() {
UserManageService.getInstance().unregisterLogin(user.getUsername());
user.notifyLogout();
login = null;
refreshPrivilege();
}
synchronized protected void logout() {
user.notifyLogout();
login = null;
refreshPrivilege();
}
public void notifyLogin(UserEntity user) {
if (!user.hasLogin())
return;
this.user = user;
login = new Date();
UserManageService.getInstance().registerLogin(user.getUsername(), this);
refreshPrivilege();
}
public UserEntity getUser() {
return user;
}
public boolean isHasLogin() {
if (user == null)
return false;
return user.hasLogin();
}
public Date getLoginTime() {
return login;
}
public Date getLastActive() {
return lastActive;
}
public Date getCreateTime() {
return createTime;
}
public String getIp() {
return ip;
}
public List<String> getTips() {
return tips;
}
public boolean hasThisPrivilege(String key) {
Boolean p = privilege.get(key);
if (p == null)
return false;
return p;
}
public void setAttribute(String name, Object value) {
attribute.put(name, value);
}
public Object getAttribute(String name) {
return attribute.get(name);
}
public String getTips(int index) {
return tips.get(index);
}
public int getTipsNumber() {
return tips.size();
}
public void addTips(String tips) {
this.tips.add(tips);
}
@Override
public int hashCode() {
if (user.getUsername() == null)
return -1;
return user.getUsername().hashCode();
}
}
Access.java URI-权限类
String path;
List<List<String>> privilege;
public Access(String path) {
this.path = path;
privilege = new ArrayList<List<String>>();
privilege.add(new ArrayList<String>());
}
public Access addPrivilege(String p, int g) {
while (g >= privilege.size()) {
privilege.add(new ArrayList<String>());
}
privilege.get(g).add(p);
return this;
}
public Access removePrivilege(String p) {
privilege.remove(p);
return this;
}
public boolean validate(AccessIdentity id) {
int j;
for (int i = 0; i < privilege.size(); i++) {
for (j = 0; j < privilege.get(i).size(); j++) {
if (!id.hasThisPrivilege(privilege.get(i).get(j))) {
break;
}
}
if (j == privilege.get(i).size() && j > 0) {
return true;
}
}
return false;
}
AccessAnalyst.java 权限分析
public class AccessAnalyst {
static String filepath;
HashMap<String, Access> map;
private static AccessAnalyst instance;
public boolean check(String url,AccessIdentity id) {
while(url!=null){
if(map.containsKey(url)){
return map.get(url).validate(id);
}
url=UpUrl(url);
}
return false;
}
private String UpUrl(String url){
if(url==null)
return null;
if(url.contains("&")){
return url.split("&")[0];
}
if(url.contains("?"))
return url.split("\\?")[0];
if(url.contains("/")){
if("/".equals(url))
return null;
String t=url.substring(0,url.lastIndexOf("/"));
if(t.length()==0)
return "/";
return t;
}
return null;
}
public static AccessAnalyst getInstance() {
if (instance == null) {
synchronized (AccessAnalyst.class) {
if (instance == null) {
instance = new AccessAnalyst();
}
}
}
return instance;
}
public static void init() {
Config config=ConfigManager.getConfig("wzz.eu.jk.Access");
String base=ConfigManager.getEnviroment("ContextRoot");
try {
filepath = base+config.getValue("path");
} catch (ConfigMissingException e) {
System.err.println("Error: AccessAnalyst init config" +
" missing parameters "+e.getMessage());
}
}
private AccessAnalyst() {
map = new HashMap<String, Access>();
init();
readFile();
}
private void readFile() {
FileMan fm = new FileMan(filepath);
List<String> lines = fm.readLines();
fm.close();
String line;
String path;
Access access;
String[] g;
String[] gs;
for (int i = 0; i < lines.size(); i++) {
line = lines.get(i);
if(line.startsWith("#"))
continue;
gs = line.split(":");
path = gs[0];
access = new Access(path);
gs = gs[1].split("\\|");
for(int j=0;j<gs.length;j++){
g=gs[j].split(",");
for(int k=0;k<g.length;k++){
access.addPrivilege(g[k], j);
System.out.println(g[k]+" added to "+path);
}
}
map.put(path, access);
}
}
}
过滤器
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest r = (HttpServletRequest) request;
AccessIdentity id = (AccessIdentity) r.getSession().getAttribute("AccessIdentity");
if (id == null) {
id = new AccessIdentity(new ClientAnalyst(r).getIpAddr());
r.getSession().setAttribute("AccessIdentity", id);
}
id.notifyActive();
String query = r.getQueryString();
String url =r.getRequestURI().replace(r.getContextPath(), "")
+ ((query != null && query.length() > 0) ? ("?" + query) : "");
AccessAnalyst aa = AccessAnalyst.getInstance();
if(aa.check(url, id)){
chain.doFilter(request, response);
if(response instanceof HttpServletResponse)
((HttpServletResponse)response).setHeader("PowerBy", "WZZ.EvolutionUnit.JavaKit");
}
else{
if(response instanceof HttpServletResponse)
((HttpServletResponse)response).setStatus(404);
}
}