您的位置:首页 > 编程语言 > Java开发

java通过Annotation配置权限

2015-05-29 09:12 423 查看
(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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: