昨日回顾
Base64
1、它是干什么的?
它可以进行编码和解码
2、能解决项目中的啥问题?
往网络上传递一个二进制文件怎么办?(图片,视频)
把一个二进制文件编码一个特殊的字符串,然后进行传递。
传输二进制—》传输字符串。
服务收到特殊字符串进行解码就能得到一个二进制。
3、他不是一个加密工具,它是一个编码解密工具
加密算法
hash,MD5,Bcrpty。
自带盐值,防止暴力破解。
四个框架都干了什么事情
ThreadLocale
1、客户端携带token发送请求
2、被拦截器拦截后开始校验token,如果token有误直接抛出异常。
3、token校验成功,从token字符串中解析出userToken对象,然后保存到THreadLocale中.
4、拦截器做放行
5、到了controller或service后,可以直接从THreadLocal中获取userToken。
6、解决安全问题还需要再controller执行之后把THreadLocal中的数据删除。
ThreadLocale是保存在当前线程里面,
一个请求发送过去,对于服务端而言就是一个线程。每个线程都有一个THreadLocal,所以他们是线程安全的。
ResponseBodyAdves
对controller返回的内容实现统一的包装(R)
RBAC权限管理系统
基于角色来控制权限的。
用户,角色,权限。
1、先找到用户的角色
2、再找到角色对应的权限,从而也就得到了用户的权限
3、权限判断的时候干的事情是
a、当前用户拥有哪些权限。 –》手里有几把药匙
b、访问这个接口需要那个权限。—》开门需要那把药匙
今日内容
画图
权限的认证
之前做的是token的认证,只要token是正确的就可以正常访问接口。
现在还要做权限,用户有了该接口的权限才能访问接口。
要做权限的认证,必须要在接口之前来完成了。在接口之前干点的事情的技术有那些?
拦截器,AOP。
使用AOP+自定义注解来实现权限的校验。
自定义注解
package com.qf.application.core.aop.annotation;
import java.lang.annotation.*;
// 这三个注解就是原注解,任何一个注解上面都会有这三个注解
@Target({ElementType.METHOD}) // 表示该注解只能加载方法上面
// *.java --->*.class --->运行
@Retention(RetentionPolicy.RUNTIME) // 该注解的作用域
@Documented // 生成JavaDoc
public @interface Permission {
}
@GetMapping("/map")
@Permission()
public Map<String, Object> testMap() {
Map<String, Object> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
return map;
}
自定义注解后,在接口上面添加@Permission表示访问这个接口需要权限才可以。
把具体的权限(锁)写入到注解中value属性即可。
@GetMapping("/map")
@Permission("test:testMap") // 访问这个接口需要test:testMap权限
public Map<String, Object> testMap() {
Map<String, Object> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
return map;
}
给自定义注解中添加一个方法
package com.qf.application.core.aop.annotation;
import java.lang.annotation.*;
// 这三个注解就是原注解,任何一个注解上面都会有这三个注解
@Target({ElementType.METHOD}) // 表示该注解只能加载方法上面
// *.java --->*.class --->运行
@Retention(RetentionPolicy.RUNTIME) // 该注解的作用域
@Documented // 生成JavaDoc
public @interface Permission {
String value() default "";
// String name() default "";
}
利用AOP的思想来控制权限
@GetMapping("/map")
@Permission("test:testMap") // 访问这个接口需要test:testMap权限
public Map<String, Object> testMap() {
Map<String, Object> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
return map;
}
}
1、什么时候做权限验证?
所有的接口都需要做吗?不一定,那些需要权限验证码?
加了@Permission的接口都需要做权限验证,如果不需要就不要在接口上面加该注解。
假设总共有10个接口,3个接口加了权限验证的注解,程序该如何判断加了权限注解的接口有那些。
2、用什么方式来实现权限校验?
使用环绕通知来实现。为什么不是前置通知呢?
前置+后置=环绕的效果。
前置通知和环绕的通知区别?
它们都可以在目标方法之前干点事情?它们区别是什么?
前置通知只是在目标方法之前执行了,但是挡不住目标方法。
环绕通知也可以目标方法之前执行,它可以挡住目标方法。
没有权限是不能调用目标方法的,所以在这个过程中需要阻断一下。
为什么环绕可以挡住而前置挡不住?
@Before
public void before(){
sout("在方法之前执行");
}
@Around
public void aroud(Jping p){
soumt("方法之前执行");
if(有权限){
// 调用目标方法
p.xxxxxxx();
}else{
// 在这里要提示用户没有方法这个接口的权限
}
soutm("目标方法之后执行");
}
package com.qf.application.core.aop.aspectj;
import com.qf.application.core.aop.annotation.Permission;
import com.qf.application.core.exception.PermissionException;
import com.qf.application.core.security.UserTokenThreadLocal;
import com.qf.application.entity.PermissionEntity;
import com.qf.application.entity.UserToken;
import com.qf.application.service.AuthoService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 权限控制的一个切面
*/
@Component // 把这个Bean交给IOC容器管理
@Aspect // 表示他是一个其切面
public class PermissionApsect {
@Autowired
private AuthoService authoService;
// exe(public * com.qf..ss.ss(...))
// 满足条件(加了@Permission注解的接口)进入这个方法
@Around(value = "@annotation(permission)")// 目标方法上面加了@Permission才会进入
public Object checkPermission(ProceedingJoinPoint proceedingJoinPoint, Permission permission) throws Throwable {
// 1.获取当前登录用户的权限
UserToken userToken = UserTokenThreadLocal.get();
Integer id = userToken.getId();
// 2.根据用户id查询他有那些权限
Set<PermissionEntity> permissionEntitySet = authoService.getPermissionSetByUserId(id);
// 3.获取方法当前接口需要那个权限
String value = permission.value();
// 4.对比
boolean flag = false; // 默认不放行
for (PermissionEntity permissionEntity : permissionEntitySet) {
if (value.equals(permissionEntity.getCode())) {
flag = true;
break;
}
}
flag = permissionEntitySet.stream().anyMatch(value::equals);
// 5、判断是否有权限
if (!flag) {
throw new PermissionException(3001, "权限不足,请联系管理员");
}
// 6、调用目标方法
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}
}
接口返回Map<String,String>报错
SpringMVC中默认使用Jackson实现对象的转换。
最终JSON字符串中的key/value转成的类型以COntroller上面返回的类型为主的。
如果controller上面返回的string/stirng,他最后把key和value全部的转成string类型,但是R中有一个code的值200(int),所以会抛出类型转换错误。
VUe.js环境搭建
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 引入Vue的JS文件 -->
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
</head>
<body>
<!-- 准备一个dev,Vue.js是单页面程序-->
<div id="app">
<!-- Vue熏染后的结果全部都在这个DIV里面展示-->
{{message}}
</div>
</body>
<script>
// 初始胡Vue实例
new Vue({
el:"#app", // 绑定视图的展示的ID
data:{ // 当前Vue实例中的数据
message: 'Hello Vue xxxxxxxxx!'
}
});
</script>
</html>