赞
踩
(1)创建一个Annotation类,该类用来作为一个Annotation提供给其他类使用,类似于@Resource
- package org.lxp.auth;
-
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
-
- /**
- * 只要在Controller上增加了这个方法的类,都需要进行权限的控制
- * @author Administrator
- *
- */
- @Retention(RetentionPolicy.RUNTIME)
- public @interface AuthClass {
- /**
- * 如果value为admin就表示这个类只能超级管理员访问
- * 如果value为login表示这个类中的方法,某些可能为相应的角色可以访问
- * @return
- */
- public String value() default "admin";
- }

(2)定义新的Annotation,这个Annotation用来控制用户可以访问哪个方法
- package org.lxp.auth;
-
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
-
- /**
- * 用来确定哪些方法由哪些角色访问
- * 属性有一个role:如果role的值为base表示这个方法可以被所有的登录用户访问
- * 如果为ROLE_PUBLISH表示只能为文章发布人员访问
- * 如果某个方法中没有加入AuthMethod就表示该方法只能被管理员所访问
- * @author Administrator
- *
- */
- @Retention(RetentionPolicy.RUNTIME)
- public @interface AuthMethod {
- public String role() default "base";
- }

(2)在Action上增加相应的访问控制,Annotation形式如下:
①
- @Controller
- @RequestMapping("/admin/user")
- @AuthClass("login")//登陆用户都可以访问
- public class UserController {
- <span style="white-space:pre"> </span>private IUserService userService;
- <span style="white-space:pre"> </span>public IUserService getUserService() {
- <span style="white-space:pre"> </span>return userService;
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>@Inject
- <span style="white-space:pre"> </span>public void setUserService(IUserService userService) {
- <span style="white-space:pre"> </span>this.userService = userService;
- <span style="white-space:pre"> </span>}
- <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
- <span style="white-space:pre"></span><pre name="code" class="java"><span style="white-space:pre"> </span>//没有写@AuthMethod这个注解,也就是<span style="font-family: Arial, Helvetica, sans-serif;">只能是管理员才能够访问</span>
@RequestMapping("/users")//
<span style="white-space:pre"> </span>//增加@AuthMethod这个注解,默认值是base,也就是所有的登陆用户都可以访问
- <span style="white-space:pre"> </span>@RequestMapping(value="/updateSelf",method=RequestMethod.GET)
- <span style="white-space:pre"> </span>@AuthMethod
- <span style="white-space:pre"> </span>public String updateSelf(Model model,HttpSession session) {
- <span style="white-space:pre"> </span>User u = (User)session.getAttribute("loginUser");
- <span style="white-space:pre"> </span>model.addAttribute(new UserDto(u));
- <span style="white-space:pre"> </span>return "user/updateSelf";
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>
- <span style="white-space:pre"> </span>@RequestMapping(value="/updateSelf",method=RequestMethod.POST)
- <span style="white-space:pre"> </span>@AuthMethod
- <span style="white-space:pre"> </span>public String updateSelf(@Valid UserDto userDto,BindingResult br,Model model,HttpSession session) {
- <span style="white-space:pre"> </span>if(br.hasErrors()) {
- <span style="white-space:pre"> </span>return "user/updateSelf";
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>User ou = userService.load(userDto.getId());
- <span style="white-space:pre"> </span>ou.setNickname(userDto.getNickname());
- <span style="white-space:pre"> </span>ou.setPhone(userDto.getPhone());
- <span style="white-space:pre"> </span>ou.setEmail(userDto.getEmail());
- <span style="white-space:pre"> </span>userService.update(ou);
- <span style="white-space:pre"> </span>session.setAttribute("loginUser", ou);
- <span style="white-space:pre"> </span>return "redirect:/admin/user/showSelf";
- <span style="white-space:pre"> </span>}

②
- @Controller
- @AuthClass("login")
- @RequestMapping("/admin/topic")
- public class TopicController {
- <pre name="code" class="java"><span style="white-space:pre"> </span>//增加role属性,说明只有文章发布人员可以访问
@RequestMapping("/add")@AuthMethod(role="ROLE_PUBLISH")public void add() {}@RequestMapping("/delete")@AuthMethod(role="ROLE_PUBLISH")public void delete() {}@RequestMapping("/audit")@AuthMethod(role="ROLE_AUDIT")public void audit() {}}
(3)基于方法的控制,当用户通过某个形式能够确定它访问的是哪个类的哪个方法,如访问/admin/topic/delete那么就会访问到TopicController的delete方法,这样的形式我们可以考虑在过滤器中获取用户访问的类的方法,然后看该方法有没有用户角色相对应的权限
①首先通过反射,获取到注解名称:使用该注解的方法这养一个键值对
- package org.lxp.auth;
- import java.io.File;
- import java.io.FilenameFilter;
- import java.lang.reflect.Method;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- public class AuthUtil {
- /**
- * 初始化系统的角色所访问的功能信息
- * @return
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static Map<String,Set<String>> initAuth(String pname) {
- try {
- //存储的是如:{ROLE_PUBLISH:[org.lxp.controller.TopicController.delete,org.lxp.controller.TopicController.add],
- //base:[org.lxp.controller.AdminController.list,org.lxp.controller.AdminController.update]}
- Map<String,Set<String>> auths = new HashMap<String, Set<String>>();
- String[] ps = getClassByPackage(pname);
- for(String p:ps) {
- //得到所有类的名称,如org.lxp.controller.AdminController
- String pc = pname+"."+p.substring(0,p.lastIndexOf(".class"));
- //得到了类的class对象
- Class clz = Class.forName(pc);
- //判断哪些类有@AuthClass这个注解
- if(!clz.isAnnotationPresent(AuthClass.class)) continue;
- // System.out.println(pc);
- //获取每个类中的方法,以此确定哪些角色可以访问哪些方法
- Method[] ms = clz.getDeclaredMethods();
- /*
- * 遍历method来判断每个method上面是否存在相应的AuthMethd
- * 如果存在就直接将这个方法存储到auths中,如果不存在就不存储
- * 不存储就意味着该方法只能由超级管理员访问
- */
- for(Method m:ms) {
- if(!m.isAnnotationPresent(AuthMethod.class)) continue;
- //如果存在就要获取这个Annotation
- AuthMethod am = m.getAnnotation(AuthMethod.class);
- String role = am.role();
- Set<String> actions = auths.get(role);
- if(actions==null) {
- actions = new HashSet<String>();
- auths.put(role, actions);
- }
- //将那个包里面的哪个类中的哪个方法加入到actions中
- actions.add(pc+"."+m.getName());
- }
- }
- return auths;
-
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
- /**
- * 根据包获取所有的类
- * @param pname
- * @return
- */
- private static String[] getClassByPackage(String pname) {
- String pr = pname.replace(".", "/");
- //能够得到包的绝对路径,如:d:/workspases/cms-web/target/classes/org/lxp/controller
- String pp = AuthUtil.class.getClassLoader().getResource(pr).getPath();
- File file = new File(pp);
- String[] fs = file.list(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- if(name.endsWith(".class")) return true;//返回所有的类
- return false;
- }
- });
- return fs;
- }
- public static void main(String[] args) {
- System.out.println(initAuth("org.lxp.controller"));
- }
- }

②何时对上面的角色信息进行加载呢?项目初始化的时候就应该加载好,这样效率会比较高
- package org.lxp.web;
- import java.util.Map;
- import java.util.Set;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import org.lxp.auth.AuthUtil;
- import org.springframework.web.context.WebApplicationContext;
- import org.springframework.web.context.support.WebApplicationContextUtils;
- public class InitServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- private static WebApplicationContext wc;
- @Override
- public void init(ServletConfig config) throws ServletException {
- super.init(config);
- //初始化spring的工厂,可以在任意的servlet或者filter中使用spring的工厂
- wc = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
- //初始化权限信息
- Map<String,Set<String>> auths = AuthUtil.initAuth("org.lxp.controller");//后面可以扩展为多个
- this.getServletContext().setAttribute("allAuths", auths);
- System.out.println("------------------------系统初始化成功:"+auths+"-----------------------------");
- }
-
- public static WebApplicationContext getWc() {
- return wc;
- }
- }

③修改web.xml,增加一个servlet,在启动的时候就会将相应角色可以访问哪些方法加载好了
- <servlet>
- <servlet-name>initServlet</servlet-name>
- <servlet-class>org.lxp.web.InitServlet</servlet-class>
- <load-on-startup>1</load-on-startup><!-- 初始化的时候就执行 -->
- </servlet>
- @RequestMapping(value="/login",method=RequestMethod.POST)
- public String login(String username,String password,String checkcode,Model model,HttpSession session) {
- String cc = (String)session.getAttribute("cc");
- if(!cc.equals(checkcode)) {
- model.addAttribute("error","验证码出错,请重新输入");
- return "admin/login";
- }
- User loginUser = userService.login(username, password);
- session.setAttribute("loginUser", loginUser);
- List<Role> rs = userService.listUserRoles(loginUser.getId());
- boolean isAdmin = isAdmin(rs);
- session.setAttribute("isAdmin", isAdmin);
- if(!isAdmin)
- session.setAttribute("allActions", getAllActions(rs, session));
- session.removeAttribute("cc");
- return "redirect:/admin";
- }
-
- @SuppressWarnings("unchecked")
- private Set<String> getAllActions(List<Role> rs,HttpSession session) {
- Set<String> actions = new HashSet<String>();
- Map<String,Set<String>> allAuths = (Map<String,Set<String>>)session.getServletContext().getAttribute("allAuths");
- actions.addAll(allAuths.get("base"));//所有登录用户都可以访问的权限
- for(Role r:rs) {
- if(r.getRoleType()==RoleType.ROLE_ADMIN) continue;
- actions.addAll(allAuths.get(r.getRoleType().name()));
- }
- return actions;
- }
-
- private boolean isAdmin(List<Role> rs) {
- for(Role r:rs) {
- if(r.getRoleType()==RoleType.ROLE_ADMIN) return true;
- }
- return false;
- }

(5)访问该功能之前要判断当前session(上面存储的allSessions)中的值能否访问该功能,使用spring的拦截器
①
- package org.lxp.web;
- import java.util.Set;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import org.lxp.cms.model.CmsException;
- import org.lxp.cms.model.User;
- import org.springframework.web.method.HandlerMethod;
- import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
- public class AuthInterceptor extends HandlerInterceptorAdapter {
- @SuppressWarnings("unchecked")
- @Override
- //提交给任何一个对象之前执行
- public boolean preHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler) throws Exception {
- HttpSession session = request.getSession();
- HandlerMethod hm = (HandlerMethod)handler;//可通过这个对象获取值
- System.out.println(hm.getBean().getClass.getName()+"."+hm.getMethod().getName());
- User user = (User)session.getAttribute("loginUser");
- if(user==null) {
- response.sendRedirect(request.getContextPath()+"/login");
- } else {
- boolean isAdmin = (Boolean)session.getAttribute("isAdmin");
- if(!isAdmin) {
- //不是超级管理人员,就需要判断是否有权限访问某些功能
- Set<String> actions = (Set<String>)session.getAttribute("allActions");
- String aname = hm.getBean().getClass().getName()+"."+hm.getMethod().getName();
- if(!actions.contains(aname)) throw new CmsException("没有权限访问该功能");
- }
- }
- return super.preHandle(request, response, handler);
- }
- /*
- //提交给视图执行
- public boolean postHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception{
- super.postHandle(request, response, handler, modelAndView);
- }
- //提交完成后用来释放资源
- public boolean afterCompletion(HttpServletRequest request,
- HttpServletResponse response, Object handler,Exception ex) throws Exception{
- super.afterCompletion(request, response, handler, ex);
- }*/
- }

②在cms-servlet.xml中配置拦截器,启动了之后,上面的程序
System.out.println(hm.getBean().getClass.getName()+"."+hm.getMethod().getName());
首先会输出访问的方法名:如org.lxp.controller.UserController.list
- <span style="white-space:pre"> </span><mvc:interceptors>
- <!-- 这个地方配置的是全局拦截器 --><!-- <bean></bean>-->
- <mvc:interceptor><!-- 配置某一写方法,使用拦截器 -->
- <mvc:mapping path="/admin/**"/>
- <bean class="org.lxp.web.AuthInterceptor"/>
- </mvc:interceptor>
- </mvc:interceptors>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。