`
obullxl
  • 浏览: 183385 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

通过Java注解实现安全控制

    博客分类:
  • Java
阅读更多

 想学习下SpringSecurity,看了下用户指南文档,觉得SpringSecurity的配置太多,并且有点复杂。一般在权限控制中,对资源访问的权限一般分为组权限(也有称角色,它包含多个单个的权限)和单个权限,那么我们完全可以在访问资源时,通过申明(Java注解)该资源所需的权限就可以达到目的了。


Java注解其实一直伴随着我们,在Java类中,我们经常会看到“@Override”、“@SuppressWarnings”等字符串,它们就是Java注解。就Java注解本身而言,它是不会对所注解的目标(类型,属性,方法,参数,构造函数,局部变量,注解和包)产生任何影响的,但它可配合其它工具(比如Eclipse,加上@SuppressWarnings(“unckecked”)后,那条黄色的警告线就消失了)或是程序(比如对属性加上@Autowire,则Spring就帮我们注入了)对注解目标产生作用。


一、定义注解类
@Target( { ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SecurityControl {
    public String[] role() default "";
    public boolean roleOr() default true;
    public String[] perm() default "";
    public boolean permOr() default false;
}
说明:Java代码去除了文件说明、版权、注释等内容。
 注解“SecurityControl”它有三个注解来说明本注解:
 Target:指示了SecurityControl可以注解的目标(类型,属性,方法,参数,构造函数,局部变量,注解和包),本注解只有类型和方法;
 Retention:指示了SecurityControl注解所适用的范围(源代码?类文件?运行期),因为要在VM运行的时候读取注解,所以本注解是运行期;
 Documented:指示了是加把本注解加到生成的Java文档中(JavaDoc),本注解加入。
 注解“SecurityControl”有四个属性:
 role[]:资源的组权限;
 roleOr:组权限是不是或关系,即只要满足其中之一即可,默认为是;
 perm[]:单个权限组;
 permOr:单个权限是不是或关系,默认为否,即全部的单个权限必须全部满足才行。

 

 二、权限异常类
 当权限不满足时,抛出异常,这样系统可以捕捉该异常,然后做相应的处理。
public class SecurityControlException extends RuntimeException {
    private static final long serialVersionUID = -8065906692358500801L;
   
    public SecurityControlException() {
    }
   
    public SecurityControlException(String errMsg) {
        super(errMsg);
    }
}
 该异常可以带一个异常消息,比如可以说明在进行什么操作时抛出该异常。

 

 三、权限持有类
public class SecurityControlHolder {
    private static final ThreadLocal<Set<String>> roles = new ThreadLocal<Set<String>>();
    private static final ThreadLocal<Set<String>> perms = new ThreadLocal<Set<String>>();
   
    public static void set(Set<String> rs, Set<String> ps) {
        roles.set(rs);
        perms.set(ps);
    }
   
    public static Set<String> getRoles() {
        return roles.get();
    }
   
    public static Set<String> getPerms() {
        return perms.get();
    }
   
    public static void clear() {
        roles.set(null);
        perms.set(null);
    }
   
    public static void checkPermission(SecurityControl sc) {
        if (checkRoles(sc) && checkPerms(sc)) {
            return;
        }
       
        throw new SecurityControlException("访问操作拒绝.");
    }
   
    private static boolean checkRoles(SecurityControl sc) {
        if (sc == null) {
            return true;
        }
       
        String[] roles = sc.role();
        if (roles == null || roles.length == 0) {
            return true;
        }
        List<String> list = new ArrayList<String>();
        for (String role : roles) {
            if (role != null && role.trim().length() > 0) {
                list.add(role.trim());
            }
        }
        if (list.isEmpty()) {
            return true;
        }
       
        Set<String> rs = getRoles();
        if (sc.roleOr()) {
            for (String role : roles) {
                if (rs.contains(role)) {
                    return true;
                }
            }
        } else {
            for (String role : roles) {
                if (!rs.contains(role)) {
                    return false;
                }
            }
            return true;
        }
       
        return false;
    }
   
    private static boolean checkPerms(SecurityControl sc) {
        if (sc == null) {
            return true;
        }
       
        String[] perms = sc.perm();
        if (perms == null || perms.length == 0) {
            return true;
        }
        List<String> list = new ArrayList<String>();
        for (String perm : perms) {
            if (perm != null && perm.trim().length() > 0) {
                list.add(perm.trim());
            }
        }
        if (list.isEmpty()) {
            return true;
        }
       
        Set<String> ps = getPerms();
        if (sc.permOr()) {
            for (String perm : perms) {
                if (ps.contains(perm)) {
                    return true;
                }
            }
        } else {
            for (String perm : perms) {
                if (!ps.contains(perm)) {
                    return false;
                }
            }
            return true;
        }
       
        return false;
    }
}
 每次验证权限“checkPermission(SecurityControl sc)”都是先验证组“checkRoles(SecurityControl sc)”,在组权限通过的情况下,再验证单个权限“checkPerms(SecurityControl sc)”,只有在组和单个权限都通过的情况下,才有权限访问资源,否则抛出权限不足异常(SecurityControlException)。

 

 四、访问切面类
 上面三步已经把准备工作做好了:我们可以通过注解来标示资源的权限,通过捕捉异常来决定当权限不足时做什么,可以通过一个简单的持有类来保持访问者的权限。现在还剩下最后一项工作:这个注解如何工作?可以通过拦截方法来达到该目的。
public class SecurityControlInterceptor implements MethodInterceptor {
    private static final Logger logger = Logger.getLogger(SecurityControlInterceptor.class);
   
  
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Class<?> clazz = method.getDeclaringClass();
       
        if (logger.isInfoEnabled()) {
            logger.info("Start Monitor: " + this.dumpInvocation(clazz, method, invocation.getArguments()));
        }
       
        SecurityControl sc = clazz.getAnnotation(SecurityControl.class);
        if (logger.isInfoEnabled()) {
            logger.info("Class SecurityControl: " + this.dumpSecurityControl(sc));
        }
       
        // 验证类安全
        SecurityControlHolder.checkPermission(sc);
       
        sc = method.getAnnotation(SecurityControl.class);
        if (logger.isInfoEnabled()) {
            logger.info("Method SecurityControl: " + this.dumpSecurityControl(sc));
        }
       
        // 验证方法安全
        SecurityControlHolder.checkPermission(sc);
       
        return invocation.proceed();
    }
   
    private String dumpInvocation(Class<?> clazz, Method method, Object[] args) {
        StringBuilder txt = new StringBuilder();
        txt.append("[Class: ").append(clazz.getSimpleName()).append("]");
        txt.append("[Method: ").append(method.getName()).append("]");
        txt.append("[Args: ").append(Arrays.toString(args)).append("]");
       
        return txt.toString();
    }
   
    private String dumpSecurityControl(SecurityControl sc) {
        if (sc != null) {
            return sc.toString();
        }
        return "null";
    }
}


 最后就是在Spring中配置拦截器。
 <bean id="serviceSecurityInterceptor" class="com.alipay.test.security.SecurityControlInterceptor" />
 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  <property name="interceptorNames">
   <list>
    <value>serviceSecurityInterceptor</value>
   </list>
  </property>
  <property name="beanNames">
   <value>*Service</value>
  </property>
 </bean>
 拦截器会拦截以Service结尾的类的方法。

 

 五、资源类(Service类)
@SecurityControl(role = { "ROLE_ADMIN", "ROLE_MANAGER" })
public interface SecurityService {
   
    public String getServiceName();
   
    @SecurityControl(perm = { "PERM_CREATE" })
    public void createService(String service);
   
    @SecurityControl(perm = { "PERM_READ" })
    public String getService();
}
 由注解可以看出:
1、 访问该类需要组权限:ROLE_ADMIN或是ROLE_MANAGER,只有该组权限满足后,才能进行类方法的调用;
2、访问方法createService()需要PERM_CREATE单个权限;
 3、访问方法getService()需要PERM_READ权限;
 4、访问方法getServiceName()除了类所需要的权限外,不需要额外权限。
 该接口的实现类:
@Component("securityService")
public class SecurityServiceImpl implements SecurityService {
   
    private String service = SecurityServiceImpl.class.getName();
   
    /**
     * @see com.aboy.SecurityService.test.annotation.service.AnnotationService#createService()
     */
    public void createService(String service) {
        this.service = service;
    }
   
    /**
     * @return
     * @see com.aboy.SecurityService.test.annotation.service.AnnotationService#getService()
     */
    public String getService() {
        return this.service;
    }
   
    /**
     * @return
     * @see com.aboy.SecurityService.test.annotation.service.AnnotationService#getServiceName()
     */
    public String getServiceName() {
        return "ServiceName";
    }
   
}

 

 六、测试
 @Test
public void testSecurityControl() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/security-context.xml");
        AnnotationService service = ctx.getBean(SecurityService.class);
       
        Set<String> roles = new HashSet<String>();
        roles.add("ROLE_ADMIN");
       
        Set<String> perms = new HashSet<String>();
        perms.add("PERM_READ");
       
        SecurityControlHolder.set(roles, perms);
       
        logger.info(service.getService());
        logger.info(service.getServiceName());
        service.createService(AnnotationServiceTest.class.getName());
        logger.info(service.getService());
    }


 运行用例发现,不通过,原因里没有PERM_CREATE权限。

 

 到此,整个注解的学习与使用已经结束了。整个权限部分,只有四个主要的类,它们完成的功能相当的简单:拦截以Service结尾的类的方法调用,获取该类和调用的方法的权限,判断权限,如果权限验证通过,则程序继续往下走,否则,抛出异常。


参考资料
百度:http://www.baidu.com和谷歌:http://www.g.cn

0
2
分享到:
评论
1 楼 jiangjuliang 2012-04-19  
[b][/b][i][/i][u][/u]
引用

    [*]
[img][/img][url][/url][flash=200,200][/flash]
[align=left][/align][/size][size=medium][size=large][/size]ddd

相关推荐

    Java远程控制简单实现

    不过,你可以通过提供的博文链接访问原文,了解更多关于如何在Java中实现远程控制的具体步骤和技巧。文章可能会涵盖上述的各个方面,包括设置环境、解决常见问题以及优化远程控制系统的性能等。在实际开发中,理解并...

    java注解webservice学习第一篇

    总的来说,Java注解使得Java Web服务的开发变得更加简洁和直观,而“lib”压缩包中的库文件则提供了实现这些注解功能的底层支持。通过学习和掌握这些知识,开发者可以更高效地构建和维护Web服务应用。

    java token验证和注解方式放行

    总的来说,这个主题涵盖了身份验证、权限控制和Spring Security的使用,这些都是Java Web开发中的核心安全实践。理解并正确实施这些机制对于构建安全的Web服务至关重要。如果你在使用过程中遇到任何问题,社区的支持...

    java RMI实现代码

    本项目提供的“java RMI实现代码”包括客户端和服务器端的示例,通过清晰的代码注释帮助理解RMI的工作原理。 一、RMI的基本概念 1. 远程接口:远程接口定义了客户端和服务器之间通信的API,它是Java接口,标注了`@...

    java代码实现短信猫发短信

    当通过程序控制短信发送时,要注意隐私和安全问题。确保只有授权的用户才能访问短信猫,并且在传输敏感信息时采取加密措施。 以上就是使用Java代码实现短信猫发送短信涉及的主要技术点和注意事项。实际操作时,...

    自定义注解实现拦截sql.rar

    本示例中,“自定义注解实现拦截SQL”是关于如何通过注解来动态修改执行的SQL语句,以在其中增加特定的条件。这个功能在数据库操作中特别有用,比如在MyBatisPlus框架中,可以用来实现灵活的数据过滤或者权限控制。 ...

    基于Java代码实现支付充值的通用流程

    在本文中,我们将深入探讨如何使用Java来实现一个支付充值的通用流程。这个流程涉及到的主要技术包括控制器(Controller)、视图(View)以及工具类(Util)的使用,特别是`Controller.java`、`submit.jsp`和`...

    spring MVC 3.1 spring security 注解实现安全机制

    通过注解,我们可以实现对请求、用户角色和权限的精细控制,提高代码的整洁性和可扩展性。尽管这里没有提供具体的jar包,但了解这两个框架的核心概念和用法,对于理解和构建类似项目是非常有帮助的。在实际操作时,...

    java5.0注释详解

    `@Retention`控制注解的保留策略,如运行时或者编译时;`@Target`指定注解可以应用的程序元素类型;`@Documented`指示这个注解应当包含在生成的Javadoc中;`@Inherited`使子类继承父类的注解。 4. **枚举(Enums)*...

    java和ssh注解

    Java注解是一种元数据,它提供了一种安全的方式向编译器或JVM传递信息。常见的注解如@Override、@Deprecated、@ SuppressWarnings等,它们可以帮助开发者进行类型检查、版本控制和消除警告。自定义注解可以用于更...

    java远程桌面控制系统

    Java远程桌面控制系统是一种利用网络通信技术实现的软件应用,它允许用户通过互联网或其他网络连接,对远程计算机进行操作和管理,仿佛直接坐在那台电脑前一样。这种系统通常基于TCP/IP协议栈,采用Socket通信机制来...

    java实现简单登录注册系统

    通过学习这个系统,你可以掌握Java中的核心概念,如面向对象编程、控制流、异常处理,以及文件操作。 首先,我们需要创建用户类(User)来表示注册的用户。用户类应该包含用户名(username)和密码(password)属性...

    JAVA实现管理系统

    MyBatis框架在此基础上提供了更加便捷的操作,通过XML或注解方式配置SQL语句,实现了SQL与Java代码的分离。 3. **MVC架构**:Model-View-Controller架构是一种常见的软件设计模式,用于处理复杂的用户界面。在Java...

    java内置注解

    Java内置注解是Java语言中的一种元编程机制,它们为代码提供信息,这些信息可以被编译器或运行时环境用来执行特定的操作。...所以,这个视频教程对于想要深入了解Java注解的开发者来说,无疑是一个非常宝贵的资源。

    JAVA 去除注释的jar工具

    这些工具通常通过解析字节码来实现注释的移除,因此即使源码不可用,也能处理。 4. **反编译与再编译**:较为复杂的方法是将jar文件反编译为源码,然后使用上述源码级别的方法去除注释,最后再重新编译为jar。这种...

    jsecurity java 安全框架

    它提供了API和注解两种方式来实现安全控制,便于开发人员根据项目需求选择合适的实现方式。同时,JSecurity的模块化设计使得扩展功能变得简单,如添加新的认证源、自定义权限表达式等。 总结,JSecurity Java安全...

    java实现任务调度

    Spring提供了一个更高级的抽象层,通过Spring的配置文件(XML或注解),可以将Quartz的Job和Trigger配置成Spring的bean,从而实现轻量级Java EE企业应用的开发。 在Spring与Quartz整合的过程中,可以使用Spring的...

    Java实现多线程远程投屏并打包可执行文件(从代码到.exe)

    - 在Java中,多线程是通过`Thread`类或实现`Runnable`接口来创建和管理的。多线程允许程序同时执行多个任务,提高系统效率。 - `Thread`类提供了一系列的方法如`start()`用于启动线程,`run()`定义线程的主要逻辑...

Global site tag (gtag.js) - Google Analytics