shiro 和webservice cxf版权限控制解决方案

shiro 和webservice cxf版权限控制解决方案

说明:
1:webservice 是无状态的,所以每次登陆要求传入用户名和密码
2:由于涉及 每次都要登陆和验证,如果接口频繁调用就会形成数据库压力过大, 需要用到缓存
3:本教程用到springAOP需要一定基础
**

基础解决方案:(原理,不推荐使用)

**
1:在每一个接口类里面直接调用login方法,然后进行授权验证方法(如isPermitted)
shiro 和webservice cxf版权限控制解决方案_第1张图片
2:开启认证模式缓存(不然会每次登陆就进入数据库认证数据库请求太频繁,授权方法缓存也获取不到)

shiro 和webservice cxf版权限控制解决方案_第2张图片
3:到这来就可以调用接口了(说明:Realm是还是用的原来web网站realm,不要定义多个Realm)
最终解决方案(推荐):
问题:
一个系统Webservice接口方法有很多,如果每个接口都写接口权限验证的代码会造成代码冗余,耦合性高。
使用spring AOP 注解 解决 就像 shiro注解一样
直接上代码
1:自定义BaseMessage父类 消息类(用于接口提示 成功 错误等消息)

/**
 * 权限基类
 * 
 * @author lw冒冒
 */
public class BaseMessage {
    //代码
    private int code;
    //成功或错误信息
    private String message;
    //详细描述
    private String detail;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }
}

2:注解类(在执行方法 写@PermissionAOP: ,不会自行百度)

/**
 * 元注解
 * 
 * @author lw冒冒
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionAOP {
    public PermissionStatus PermissionStatus() default PermissionStatus.NONE;//是否需要验证
    public String PermissionDetails();//权限验证字符串
}

3:切面类(执行权限验证方法)

/**
 * 权限切面类
 * 
 * @author lw冒冒
 */
@Aspect
@Component
public class PermissionAspect {
    private static final Logger log = LoggerFactory.getLogger(PermissionAspect.class);

    @Pointcut("@annotation(com.lw.common.annotation.PermissionAOP)")//上面元注解 public @interface PermissionAOP 
    public void permissionAspect(){}

    @Around("permissionAspect()")
    public Object doGetPermission(ProceedingJoinPoint point) throws Throwable {

        Object[] objects = point.getArgs();
        System.out.println("-----------------------------参数:" + objects[0].toString());
        System.out.println("触发自定义异常AuthenticationException_________________________");
        Class method = ((MethodSignature)point.getSignature()).getReturnType();
        Class<?> nameclass = Class.forName(method.getName());
        Object object= nameclass.newInstance();
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(objects[0].toString(), objects[1].toString(), true);
            Subject subject = SecurityUtils.getSubject();
            subject.login(token);
            PermissionAOP permissionstr = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(PermissionAOP.class);//获取注解
            String strpermission = permissionstr.PermissionDetails();//获取注解权限 字符串
            if (subject.isPermitted(strpermission)) {
                Object o = point.proceed();
                return o;

            } else {
                getDeclaredField(object,"code",500);
                getDeclaredField(object,"message","没有权限");
                getDeclaredField(object,"detail","用户存在,但无授权,接口调用失败");
            }
        } catch (Exception ex) {
            //反射方式统一返回权限错误信息  @lw 2020/3/18

            getDeclaredField(object,"code",500);
            getDeclaredField(object,"message","用户名密码错误");
            return object;
        }
        return object;
    }

   
    protected void handlePermission(final JoinPoint joinPoint,Object args)
    {

    }

    /**
     * 循环向上转型, 获取对象的 DeclaredField
     * @param object : 子类对象
     * @param fieldName : 父类中的属性名
     * @return 父类中的属性对象
     */
    public  Field getDeclaredField(Object o, String fieldName,Object message){
        Field field = null ;
        Class clazz = o.getClass();
        for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName) ;
                field.setAccessible(true);
                field.set(o,message);
                return field ;
            } catch (Exception e) {
            }
        }
        return null;
    }
}

4:权限测试类
//权限测试类
/**

  • 对外接口类 要基础BaseMessage

  • @author lw冒冒
    */
    public class TestExam extends BaseMessage{
    private String teststr;

    public String getTeststr() {
    return teststr;
    }

    public void setTeststr(String teststr) {
    this.teststr = teststr;
    }
    }
    5:webservice类

//cxf版webservice 接口
/**
 * 对外接口类 要基础BaseMessage
 * 
 * @author lw冒冒
 */
@WebService(targetNamespace = "http://service.cfx.com")
public interface IWebServiceInterface {
 @WebMethod
    public TestExam WS_selectExamPcList(String username, String password);
}

/**
 * webservice 类方法(支持一个地址多个接口方法)
 * 
 * @author lw冒冒
 */
@WebService(serviceName = "exampcservice",targetNamespace = "http://service.cfx.com",endpointInterface = "com.ruoyi.system.service.IWebServiceInterface")
@Service
public class WebServiceInterface implements IWebServiceInterface {

@PermissionAOP(PermissionStatus = PermissionStatus.ABLE,PermissionDetails = "admin")
    @WebMethod
    @Override
    public TestExam WS_selectExamPcList(String username, String password)
    {
        TestExam testExam =new TestExam();
        testExam.setCode(200);
        testExam.setMessage("成功");
        return testExam;
    }
   }

结束

你可能感兴趣的:(shiro 和webservice cxf版权限控制解决方案)