SpringSecurity和JWT
SpingSecurity用于保护web安全,实现访问控制的功能,身份认证和授权操作,账号密码校验,使用token授权
JWT:可以实现跨域身份验证和授权,安全和方便
集成授权的操作流程
1.重写UserDetails中的方法getAuthorities
2.查询当前用户所有的权限信息,并返回GrantedAuthority类型的集合,在mapper接口做查询
手动获取容器中的mapper
手动使用**SpringUtils.getBean(PermissionMapper.class)**获取到对象
PermissionMapper mapper = SpringUtils.getBean(PermissionMapper.class);
判断当前用户是不是超管
是超管就分配所有的权限
List<Permission> permissions = mapper.selectAll();
ArrayList<SimpleGrantedAuthority> list = new ArrayList<>();
将权限表达式封装成SpringSecurity需要的对象,并进行返回
for (Permission permission : permissions) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission.getExpression());
list.add(authority);
}
不是超管就分配应有的权限,使用用户的id去数据库查询权限信息,使用java8的方式将数据封装成SpringSecurity这样的对象
List<String> expressions = mapper.selectExpressionsByEmpId(employee.getId());
return expressions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
3.在filter中认证的时候在UsernamePasswordAuthenticationToken中加入权限
4.使用注解开启注解支持
5.在需要权限的方法上贴@PreAuthorize(“hasAuthority(‘department:list’)”)注解
问题
由于这里使用的动态代理的代理类拿的注解,但是代理类是没有那个注解的,需要拿到父类的字节码对象才能得到这个注解,在权限的Service中进行修改
虽然是管理员,但是没有权限做任何操作
出现的原因,将前端传进来的userId可能写成id,会导致接收的参数不会对应
JWT
定义了紧凑的,自包含的方式,使用JSON对象安全传输的信息
使用session认证缺点
1.每做一次认证都会在内存中作一次记录,用户增多后的服务端的开销较大
2.会使用明文进行信息的展示,不安全
使用JWT的优势:
自包含: 负载中包含了所有的用户所需要的新信息
简洁: 数据量少,传输速度快
好处:不以明文的形式保存在浏览器
结构
标头(header):
定义令牌的类型和所使用的签名算法类型
载荷(payload)
加密用户和其他的数据
签名(signature):
保护JWT没有被篡改过,是一个盐
如何集成JWT
1.使用工具类JWTUtils
2.在spplication.yml写配置
jwt:
scret: abced
head: Authencation
3.在sEmployeeService中使用JWT生成token,并且此时方法的返回的类型改成String
//使用JWT生成token,此时这个方法返回的类型就从Employee改成String
String uuid = UUID.randomUUID().toString();
String toten = jwtUtils.createToken("uuid", uuid);
// 将登录成功之后的用户对象存到redis中
redisUtils.set("EMPLOYEE:"+uuid, JSON.toJSONString(employee), 60*60*24);
4.在过滤器中增加JWT
使用**jwtUtils.getHeade()**获取前端传进来的令牌,同时修改前端参数的获取
String token1 = httpServletRequest.getHeader(jwtUtils.getHead());
判断token中是否有值,有值就获取令牌中的uuid,用这个获取redis中的数据
if(StringUtils.hasLength(token1)){
//获取令牌中的uuid,用这个取获取redis中的数据
String uuid = jwtUtils.getToken1(token1, "uuid");
String employeeJson = redisUtils.get("EMPLOYEE:" + uuid);
//将认证后的信息对象添加到上下文对象中,供认证检查时使用
Employee employee = JSON.parseObject(employeeJson, Employee.class);
if(employee!=null){
MyUserDetails myUserDetails = new MyUserDetails();
myUserDetails.setEmployee(employee);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(employee.getUsername(), employee.getPassword(),myUserDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
}
JWT中的数据被篡改会有以下的错误,
导包错误,导spring的,同时交给统一异常处理
回顾
如何做认证
如何做授权
认证和授权的底层原理(先看)
横向看shiro,看底层原理