说明:
1:webservice 是无状态的,所以每次登陆要求传入用户名和密码
2:由于涉及 每次都要登陆和验证,如果接口频繁调用就会形成数据库压力过大, 需要用到缓存
3:本教程用到springAOP需要一定基础
**
**
1:在每一个接口类里面直接调用login方法,然后进行授权验证方法(如isPermitted)
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;
}
}