java通过Annotation配置权限

本文介绍了一种基于自定义Annotation的权限控制系统实现方法,包括创建注解、在控制器上应用注解、通过反射获取注解信息、加载角色权限以及使用Spring拦截器验证权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(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")//
public String list(Model model) {
model.addAttribute("datas",userService.findUser());
return "user/list";
}

<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>

(4)在用户登录之后就应该对用户的权限进行判断,登录后将该用户所有的权限保存到session中

@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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值