这个是一个自定义权限拦截器,虽说有Spring Security,但是还是记录下它,下篇在写Spring Security吧。
1.写两个自定义注解(功能类似于spring security的@PreAuthorize)
package com.jeff.authority;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auth {
public String[] roles();
public String description() default "";
public String url() default "";
}
package com.jeff.authority;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthClass {
public String[] defaultRoles() default {};
}
2.具体实现权限拦截的类
package com.jeff.authority;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import com.jeff.util.PropertiesUtil;
public class AuthContext {
public static HashMap<String, Set<String>> acl = new HashMap<String, Set<String>>();
public static Set<String> freeUrls = new HashSet<String>(); //不加拦截的的方法
static {
freeUrls.add("/admin/login");
freeUrls.add("/admin/mobileLogin");
freeUrls.add("/user/login");
freeUrls.add("/user/logout");
freeUrls.add("/user/getQRcode");
freeUrls.add("/user/scanLoginCode");
freeUrls.add("/user/check");
freeUrls.add("/user/mobileLogin");
freeUrls.add("/user/fingerLogin");
freeUrls.add("/exam/login");
freeUrls.add("/exam/getUserIdQRcode");
freeUrls.add("/exam/getQRcode");
freeUrls.add("/exam/scanLoginCode");
freeUrls.add("/exam/examineeFingerLogin");
freeUrls.add("/ajaxmenutree");
freeUrls.add("/news/searchNewsByPage");
freeUrls.add("/news/getOneNews");
freeUrls.add("/file/downloadAttachment");
}
/***
* 判断是否有权限调用该方法
* @param gradeId
* @param url
* @return
*/
public static boolean checkAuth(String gradeId, String url) {
// if (acl.containsKey(gradeId))
// return acl.get(gradeId).contains(url);
// else
// return freeUrls.contains(url);
if(freeUrls.contains(url)) {
return true; //先判断是否是自由访问的,如果是直接返回true
} else if (acl.containsKey(gradeId)) {
return acl.get(gradeId).contains(url);//返回该角色是否有权限调用此方法
} else {
return false;
}
}
/***
* 获取角色权限的信息 生成HashMap acl
* @param connection
* @throws SQLException
*/
public static void initAuthContext(Connection connection)
throws SQLException {
Properties properties = PropertiesUtil.getProp("jdbc.properties");
String url = properties.getProperty("jdbc_url");
String username = properties.getProperty("jdbc_username");
String password = properties.getProperty("jdbc_password");
try {
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(url, username,
password);
Statement statement = connection.createStatement();
//将所有角色和它可以调用的方法url查询出来
String sql = "select g.id as gId,f.url as url from `grade` g,`func_permit` f where FIND_IN_SET(f.id,g.func_permit_list)";
ResultSet rs = statement.executeQuery(sql);
// 添加权限对应的url串
while (rs.next()) {
String gId = rs.getString("gId");
String pUrl = rs.getString("url");
Set<String> urls;
/**
* 将权限信息生成hash
*/
if (acl.containsKey(gId)){
urls = acl.get(gId);
}
else {
urls = new HashSet<String>();
acl.put(gId, urls);
}
urls.add(pUrl);
}
rs.close();
statement.close();
connection.close();
} catch (SQLException se) {
System.out.println("数据库连接失败!");
se.printStackTrace();
}
}
}
3.写一个拦截器,项目启动时运行
package com.jeff.authority;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.jeff.util.PropertiesUtil;
/**
* 权限监听器、拦截器
* @author chen
*
*/
public class AuthListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent arg0) {
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
Properties properties = PropertiesUtil.getProp("jdbc.properties");
String url = properties.getProperty("jdbc_url");
String username = properties.getProperty("jdbc_username");
String password = properties.getProperty("jdbc_password");
try {
Connection con = DriverManager.getConnection(url, username,
password);//数据库连接
AuthUtil.initAuth(AuthUtil.pNames, con);
AuthContext.initAuthContext(con);
con.close();
} catch (SQLException se) {
System.out.println("数据库连接失败!");
se.printStackTrace();
}
}
}
4.在web.xml配置拦截器
<listener>
<description>权限初始化监听器</description>
<listener-class>com.jeff.authority.AuthListener</listener-class>
</listener>
5.默认属性文件 authority.properties
#角色表
role = grade(id,name)
#用户角色表
#user_role = user_grade(id,user_id,grade_id)
#权限表
permission = permission(id,description,URL)
#权限控制表ACL(access control list)
acl = acl(id,grade_id,permission_id)
6.写一个过滤器,使每次调用方法都判断权限
package com.jeff.mybatis.autobuild;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jeff.authority.AuthContext;
import com.jeff.common.BaseInfo;
import com.jeff.util.StringUtil;
/**
* 将分页的pager数据嵌入localthread中
*
* @author jeff he
*
*/
public class LogAndPermitFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String userId = "";
MybatisContext.setUserId(BaseInfo.GetUserId(request));
String gId = "";
String url = "";
try {
String displayName = request.getContextPath();//获取项目的根路径,即项目名
System.out.println(displayName);
url = request.getRequestURL().toString();//获取访问的url
int i = url.indexOf("/", url.indexOf(displayName) + 1);//项目名的长度
int j = url.lastIndexOf(".do");
url = url.substring(i, j);//剪切url,去掉项目名的头,和.do的尾
//System.out.println(url);
userId = BaseInfo.GetUserId(request);//获取session
gId = BaseInfo.GetUserGradeId(request);
if (StringUtil.isEmpty(userId)) {
userId = "session中没有user";
}
// 将LOG数据放入当前线程
MybatisContext.setUserId(userId);
// System.out.println(MybatisContext.getUserId());
if (AuthContext.checkAuth(gId, url)){//判断是否有权限
chain.doFilter(req, resp);
}
else {
System.out.println("目标地址:" + url + " 未授权");
request.getSession().setAttribute("info", "方法未授权,请先登录系统");
response.sendRedirect(displayName);
}
//chain.doFilter(req, resp);
} catch (Exception e) {
userId = "获取userid出现异常";
} finally {
// 清除LOG数据
MybatisContext.clearContext();
}
}
public void init(FilterConfig cfg) throws ServletException {
}
public void destroy() {
}
}
7.在web.xml配置过滤器
<filter>
<description>Log拦截器</description>
<filter-name>logAndPermitFilter</filter-name>
<filter-class>com.jeff.mybatis.autobuild.LogAndPermitFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>logAndPermitFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
至此,所有权限拦截器配置已经完成,具体使用如下
1.controller 类上使用@AuthClass
@AuthClass
@Controller
@RequestMapping("admin")
public class AdminController {
..........
}
2.方法上使用@Auth
@RequestMapping("changeType")
@ResponseBody
@Auth(roles = { "业务主管机构"}, description = "业务主管修改当前的type类型")
public ResultMap changeType(HttpServletRequest request, String type) {
........
}