第4章 权限管理与jwt鉴权
学习目标: 理解权限管理的需求以及设计思路 实现角色分配和权限分配 理解常见的认证机制 能够使用JWT完成微服务Token签发与验证
1 权限管理
1.1 需求分析 完成权限(菜单,按钮(权限点),API接口)的基本操作
权限与菜单,菜单与按钮,菜单与API接口都是一对一关系。为了方便操作,在SAAS-HRM系统的表设计中,采用 基于共享主键的形式实现一对一关系维护,并且数据库约束,一切的关系维护需要程序员在代码中实现。 1.2 后端实现 1.2.1 实体类 在系统微服务中创建权限,菜单,按钮(权限点),API对象的实体类
角色对应得Controller接口
@RestController
@RequestMapping("/sys")
public class RoleController extends BaseController{
@Autowired
private RoleService roleService;
/**
* 分配权限
*/
@RequestMapping(value = "/role/assignPrem", method = RequestMethod.PUT)
public Result assignPrem(@RequestBody Map<String,Object> map) {
//1.获取被分配的角色的id
String roleId = (String) map.get("id");
//2.获取到权限的id列表
List<String> permIds = (List<String>) map.get("permIds");
//3.调用service完成权限分配
roleService.assignPerms(roleId,permIds);
return new Result(ResultCode.SUCCESS);
}
//添加角色
@RequestMapping(value = "/role", method = RequestMethod.POST)
public Result add(@RequestBody Role role) throws Exception {
role.setCompanyId(companyId);
roleService.save(role);
return Result.SUCCESS();
}
//更新角色
@RequestMapping(value = "/role/{id}", method = RequestMethod.PUT)
public Result update(@PathVariable(name = "id") String id, @RequestBody Role role) throws Exception {
roleService.update(role);
return Result.SUCCESS();
}
//删除角色
@RequestMapping(value = "/role/{id}", method = RequestMethod.DELETE)
public Result delete(@PathVariable(name = "id") String id) throws Exception {
roleService.delete(id);
return Result.SUCCESS();
}
/**
* 根据ID获取角色信息
*/
@RequestMapping(value = "/role/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable(name = "id") String id) throws Exception {
Role role = roleService.findById(id);
RoleResult roleResult = new RoleResult(role);
return new Result(ResultCode.SUCCESS,roleResult);
}
/**
* 分页查询角色
*/
@RequestMapping(value = "/role", method = RequestMethod.GET)
public Result findByPage(int page,int pagesize,Role role) throws Exception {
Page<Role> searchPage = roleService.findByPage(companyId, page, pagesize);
PageResult<Role> pr = new PageResult(searchPage.getTotalElements(),searchPage.getContent());
return new Result(ResultCode.SUCCESS,pr);
}
@RequestMapping(value="/role/list" ,method=RequestMethod.GET)
public Result findAll() throws Exception {
List<Role> roleList = roleService.findAll(companyId);
return new Result(ResultCode.SUCCESS,roleList);
}
}
角色管理测试
新增角色:
权限分配接口
@RequestMapping(value="/sys")
public class PermissionController {
@Autowired
private PermissionService permissionService;
/**
* 保存
*/
@RequestMapping(value = "/permission", method = RequestMethod.POST)
public Result save(@RequestBody Map<String,Object> map) throws Exception {
permissionService.save(map);
return new Result(ResultCode.SUCCESS);
}
/**
* 修改
*/
@RequestMapping(value = "/permission/{id}", method = RequestMethod.PUT)
public Result update(@PathVariable(value = "id") String id, @RequestBody Map<String,Object> map) throws Exception {
//构造id
map.put("id",id);
permissionService.update(map);
return new Result(ResultCode.SUCCESS);
}
/**
* 查询列表
*/
@RequestMapping(value = "/permission", method = RequestMethod.GET)
public Result findAll(@RequestParam Map map) {
List<Permission> list = permissionService.findAll(map);
return new Result(ResultCode.SUCCESS,list);
}
/**
* 根据ID查询
*/
@RequestMapping(value = "/permission/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable(value = "id") String id) throws Exception {
Map map = permissionService.findById(id);
return new Result(ResultCode.SUCCESS,map);
}
分配权限测试:
权限增删改查
DAO接口:
public interface PermissionDao extends JpaRepository<Permission, String>, JpaSpecificationExecutor<Permission> {
List<Permission> findByTypeAndPid(int type,String pid);
}
/**
* 企业数据访问接口
*/
public interface PermissionMenuDao extends JpaRepository<PermissionMenu, String>, JpaSpecificationExecutor<PermissionMenu> {
}
/**
* 企业数据访问接口
*/
public interface PermissionPointDao extends JpaRepository<PermissionPoint, String>, JpaSpecificationExecutor<PermissionPoint> {
}
Service接口:
/**
* 1.保存权限
*/
public void save(Map<String,Object> map) throws Exception {
//设置主键的值
String id = idWorker.nextId()+"";
//1.通过map构造permission对象
Permission perm = BeanMapUtils.mapToBean(map,Permission.class);
perm.setId(id);
//2.根据类型构造不同的资源对象(菜单,按钮,api)
int type = perm.getType();
switch (type) {
case PermissionConstants.PERMISSION_MENU:
PermissionMenu menu = BeanMapUtils.mapToBean(map,PermissionMenu.class);
menu.setId(id);
permissionMenuDao.save(menu);
break;
case PermissionConstants.PERMISSION_POINT:
PermissionPoint point = BeanMapUtils.mapToBean(map,PermissionPoint.class);
point.setId(id);
permissionPointDao.save(point);
break;
case PermissionConstants.PERMISSION_API:
PermissionApi api = BeanMapUtils.mapToBean(map,PermissionApi.class);
api.setId(id);
permissionApiDao.save(api);
break;
default:
throw new CommonException(ResultCode.FAIL);
}
//3.保存
permissionDao.save(perm);
}
/**
* 2.更新权限
*/
public void update(Map<String,Object> map) throws Exception {
Permission perm = BeanMapUtils.mapToBean(map,Permission.class);
//1.通过传递的权限id查询权限
Permission permission = permissionDao.findById(perm.getId()).get();
permission.setName(perm.getName());
permission.setCode(perm.getCode());
permission.setDescription(perm.getDescription());
permission.setEnVisible(perm.getEnVisible());
//2.根据类型构造不同的资源
int type = perm.getType();
switch (type) {
case PermissionConstants.PERMISSION_MENU:
PermissionMenu menu = BeanMapUtils.mapToBean(map,PermissionMenu.class);
menu.setId(perm.getId());
permissionMenuDao.save(menu);
break;
case PermissionConstants.PERMISSION_POINT:
PermissionPoint point = BeanMapUtils.mapToBean(map,PermissionPoint.class);
point.setId(perm.getId());
permissionPointDao.save(point);
break;
case PermissionConstants.PERMISSION_API:
PermissionApi api = BeanMapUtils.mapToBean(map,PermissionApi.class);
api.setId(perm.getId());
permissionApiDao.save(api);
break;
default:
throw new CommonException(ResultCode.FAIL);
}
//3.保存
permissionDao.save(permission);
}
/**
* 3.根据id查询
* //1.查询权限
* //2.根据权限的类型查询资源
* //3.构造map集合
*/
public Map<String, Object> findById(String id) throws Exception {
Permission perm = permissionDao.findById(id).get();
int type = perm.getType();
Object object = null;
if(type == PermissionConstants.PERMISSION_MENU) {
object = permissionMenuDao.findById(id).get();
}else if (type == PermissionConstants.PERMISSION_POINT) {
object = permissionPointDao.findById(id).get();
}else if (type == PermissionConstants.PERMISSION_API) {
object = permissionApiDao.findById(id).get();
}else {
throw new CommonException(ResultCode.FAIL);
}
Map<String, Object> map = BeanMapUtils.beanToMap(object);
map.put("name",perm.getName());
map.put("type",perm.getType());
map.put("code",perm.getCode());
map.put("description",perm.getDescription());
map.put("pid",perm.getPid());
map.put("enVisible",perm.getEnVisible());
return map;
}
/**
* 4.查询全部
* type : 查询全部权限列表type:0:菜单 + 按钮(权限点) 1:菜单2:按钮(权限点)3:API接口
* enVisible : 0:查询所有saas平台的最高权限,1:查询企业的权限
* pid :父id
*/
public List<Permission> findAll(Map<String, Object> map) {
//1.需要查询条件
Specification<Permission> spec = new Specification<Permission>() {
/**
* 动态拼接查询条件
* @return
*/
public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
//根据父id查询
if(!StringUtils.isEmpty(map.get("pid"))) {
list.add(criteriaBuilder.equal(root.get("pid").as(String.class),(String)map.get("pid")));
}
//根据enVisible查询
if(!StringUtils.isEmpty(map.get("enVisible"))) {
list.add(criteriaBuilder.equal(root.get("enVisible").as(String.class),(String)map.get("enVisible")));
}
//根据类型 type
if(!StringUtils.isEmpty(map.get("type"))) {
String ty = (String) map.get("type");
CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("type"));
if("0".equals(ty)) {
in.value(1).value(2);
}else{
in.value(Integer.parseInt(ty));
}
list.add(in);
}
return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
}
};
return permissionDao.findAll(spec);
}
/**
* 5.根据id删除
* //1.删除权限
* //2.删除权限对应的资源
*
*/
public void deleteById(String id) throws Exception {
//1.通过传递的权限id查询权限
Permission permission = permissionDao.findById(id).get();
permissionDao.delete(permission);
//2.根据类型构造不同的资源
int type = permission.getType();
switch (type) {
case PermissionConstants.PERMISSION_MENU:
permissionMenuDao.deleteById(id);
break;
case PermissionConstants.PERMISSION_POINT:
permissionPointDao.deleteById(id);
break;
case PermissionConstants.PERMISSION_API:
permissionApiDao.deleteById(id);
break;
default:
throw new CommonException(ResultCode.FAIL);
}
}
新增权限测试界面
角色分配后面的权限控制:
分配权限:
常见的认证机制:JWT
/**
* 通过jjwt创建token
*/
public static void main(String[] args) {
JwtBuilder jwtBuilder = Jwts.builder().setId("88").setSubject("小白")
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, "ihrm")
.claim("companyId","123456")
.claim("companyName","江苏传智播客教育股份有限公司")
;
String token = jwtBuilder.compact();
System.out.println(token);
}
测试:
解析JWT token:
/**
* 解析jwtToken字符串
*/
public static void main(String[] args) {
String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4OCIsInN1YiI6IuWwj-eZvSIsImlhdCI6MTYwNjMwMjczNSwiY29tcGFueUlkIjoiMTIzNDU2IiwiY29tcGFueU5hbWUiOiLmsZ_oi4_kvKDmmbrmkq3lrqLmlZnogrLogqHku73mnInpmZDlhazlj7gifQ.zCZVIIFTX26unAMX1egyPOtwtrscPFCTtYWhKN7DUwo";
Claims claims = Jwts.parser().setSigningKey("ihrm").parseClaimsJws(token).getBody();
//私有数据存放在claims
System.out.println(claims.getId());
System.out.println( claims.getSubject());
System.out.println(claims.getIssuedAt());
//解析自定义claim中的内容
String companyId = (String)claims.get("companyId");
String companyName = (String)claims.get("companyName");
System.out.println(companyId + "---" + companyName);
}
JWT集成hrm系统
public String createJwt(String id, String name, Map<String,Object> map) {
//1.设置失效时间
long now = System.currentTimeMillis();//当前毫秒
long exp = now + ttl;
//2.创建jwtBuilder
JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(name)
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, key);
//3.根据map设置claims
for(Map.Entry<String,Object> entry : map.entrySet()) {
jwtBuilder.claim(entry.getKey(),entry.getValue());
}
jwtBuilder.setExpiration(new Date(exp));
//4.创建token
String token = jwtBuilder.compact();
return token;
}
/**
* 解析token字符串获取clamis
*/
public Claims parseJwt(String token) {
Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
return claims;
}
用户登录接口信息
/**
* 用户登录
* 1.通过service根据mobile查询用户
* 2.比较password
* 3.生成jwt信息
*
*/
@RequestMapping(value="/login",method = RequestMethod.POST)
public Result login(@RequestBody Map<String,String> loginMap) {
String mobile = loginMap.get("mobile");
String password = loginMap.get("password");
User user = userService.findByMobile(mobile);
//登录失败
if(user == null || !user.getPassword().equals(password)) {
return new Result(ResultCode.MOBILEORPASSWORDERROR);
}else {
//登录成功
Map<String,Object> map = new HashMap<>();
map.put("companyId",user.getCompanyId());
map.put("companyName",user.getCompanyName());
String token = jwtUtils.createJwt(user.getId(), user.getUsername(), map);
return new Result(ResultCode.SUCCESS,token);
}
}
POSTMan测试:
密码正确的测试:
解析Token: