参考:https://how2j.cn/k/shiro/shiro-plan/1732.html#nowhere
代码下载
链接:https://pan.baidu.com/s/1lbQRPRaSedPQwXK-sbN66w
提取码:k2pa
1.Shiro介绍
一个简洁的网络安全框架
2.shiro 如何进行加密
MD5加密算法
项目中对于密码通常采用非对称加密,什么是非对称呢?就是不可逆的,而 md5 就是这样一个算法。
简单测试一下:
public static void main(String[] args) {
String password = "123";
String encodedPassword = new Md5Hash(password).toString();
System.out.println(encodedPassword);
}
盐
如果单纯的使用MD5加密算法也有缺陷,当密码太简单时可能会被穷举破解。
盐就是一个随机数,我在密码后加上一个一个随机字符串,即使相同的密码在数据库里的存储也不同,这就增大了安全性。盐也会保存在数据库中,每个用户的都不一样。
3.springboot 整合 shiro
1.数据库准备
#
# Structure for table "permission"
#
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`desc_` varchar(100) DEFAULT NULL,
`url` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
#
# Data for table "permission"
#
INSERT INTO `permission` VALUES (1,'addProduct','增加产品','/addProduct'),(2,'deleteProduct','删除产品','/deleteProduct'),(3,'editeProduct','编辑产品','/editeProduct'),(4,'updateProduct','修改产品','/updateProduct'),(5,'listProduct','查看产品','/listProduct'),(6,'addOrder','增加订单','/addOrder'),(7,'deleteOrder','删除订单','/deleteOrder'),(8,'editeOrder','编辑订单','/editeOrder'),(9,'updateOrder','修改订单','/updateOrder'),(10,'listOrder','查看订单','/listOrder');
#
# Structure for table "role"
#
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`desc_` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
#
# Data for table "role"
#
INSERT INTO `role` VALUES (1,'admin','超级管理员'),(2,'productManager','产品管理员'),(3,'orderManager','订单管理员');
#
# Structure for table "role_permission"
#
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`rid` bigint(20) DEFAULT NULL,
`pid` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=57 DEFAULT CHARSET=utf8;
#
# Data for table "role_permission"
#
INSERT INTO `role_permission` VALUES (1,1,1),(2,1,2),(3,1,3),(4,1,4),(5,1,5),(6,1,6),(7,1,7),(8,1,8),(9,1,9),(10,1,10),(11,2,1),(12,2,2),(13,2,3),(14,2,4),(15,2,5),(50,3,10),(51,3,9),(52,3,8),(53,3,7),(54,3,6),(55,3,1),(56,5,11);
#
# Structure for table "user"
#
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`salt` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
#
# Data for table "user"
#
INSERT INTO `user` VALUES (1,'zhang3','a7d59dfc5332749cb801f86a24f5f590','e5ykFiNwShfCXvBRPr3wXg=='),(2,'li4','43e28304197b9216e45ab1ce8dac831b','jPz19y7arvYIGhuUjsb6sQ==');
#
# Structure for table "user_role"
#
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uid` bigint(20) DEFAULT NULL,
`rid` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8;
#
# Data for table "user_role"
#
INSERT INTO `user_role` VALUES (43,2,2),(45,1,1);
2.项目结构
3.基于url配置权限
PermissionService.java
public interface PermissionService {
public Set<String> listPermissions(String userName);
public List<Permission> list();
public void add(Permission permission);
public void delete(Long id);
public Permission get(Long id);
public void update(Permission permission);
public List<Permission> list(Role role);
/*needInterceptor 判断是否要进行拦截*/
public boolean needInterceptor(String requestURI);
/*listPermissionURLs(User user) 用来获取某个用户所拥有的权限地址集合*/
public Set<String> listPermissionURLs(String userName);
}
PermissionServiceImpl.java:
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
PermissionMapper permissionMapper;
@Autowired
UserService userService;
@Autowired
RoleService roleService;
@Autowired
RolePermissionMapper rolePermissionMapper;
@Override
public Set<String> listPermissions(String userName) {
Set<String> result = new HashSet<>();
List<Role> roles = roleService.listRoles(userName);
List<RolePermission> rolePermissions = new ArrayList<>();
for (Role role : roles) {
RolePermissionExample example = new RolePermissionExample();
example.createCriteria().andRidEqualTo(role.getId());
List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
rolePermissions.addAll(rps);
}
for (RolePermission rolePermission : rolePermissions) {
Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
result.add(p.getName());
}
return result;
}
@Override
public void add(Permission u) {
permissionMapper.insert(u);
}
@Override
public void delete(Long id) {
permissionMapper.deleteByPrimaryKey(id);
}
@Override
public void update(Permission u) {
permissionMapper.updateByPrimaryKeySelective(u);
}
@Override
public Permission get(Long id) {
return permissionMapper.selectByPrimaryKey(id);
}
@Override
public List<Permission> list() {
PermissionExample example = new PermissionExample();
example.setOrderByClause("id desc");
return permissionMapper.selectByExample(example);
}
@Override
public List<Permission> list(Role role) {
List<Permission> result = new ArrayList<>();
RolePermissionExample example = new RolePermissionExample();
example.createCriteria().andRidEqualTo(role.getId());
List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
for (RolePermission rolePermission : rps) {
result.add(permissionMapper.selectByPrimaryKey(rolePermission.getPid()));
}
return result;
}
@Override
public boolean needInterceptor(String requestURI) {
//获取所有的权限
List<Permission> ps = list();
//权限中的url与参数对照
for (Permission p : ps) {
//匹配成功说明该requestURI只有当用户拥有该权限时才可进入
if (p.getUrl().equals(requestURI))
//return true还是false看需求
return true;
}
return false;
}
/*用来获取某个用户所拥有的权限地址集合*/
@Override
public Set<String> listPermissionURLs(String userName) {
Set<String> result = new HashSet<>();
List<Role> roles = roleService.listRoles(userName);
List<RolePermission> rolePermissions = new ArrayList<>();
for (Role role : roles) {
RolePermissionExample example = new RolePermissionExample();
example.createCriteria().andRidEqualTo(role.getId());
List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
rolePermissions.addAll(rps);
}
for (RolePermission rolePermission : rolePermissions) {
Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
result.add(p.getUrl());
}
return result;
}
}
URLPathMatchingFilter(内置过滤器):
public class URLPathMatchingFilter extends PathMatchingFilter {
@Autowired
PermissionService permissionService;
@Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
String requestURI = getPathWithinApplication(request);
System.out.println("requestURI:" + requestURI);
Subject subject = SecurityUtils.getSubject();
// 如果没有登录,就跳转到登录页面
if (!subject.isAuthenticated()) {
WebUtils.issueRedirect(request, response, "/login");
return false;
}
// 看看这个路径权限里有没有维护,如果没有维护,一律放行(也可以改为一律不放行)
boolean needInterceptor = permissionService.needInterceptor(requestURI);
if (!needInterceptor) {
return true;
} else {
boolean hasPermission = false;
String userName = subject.getPrincipal().toString();
Set<String> permissionUrls = permissionService.listPermissionURLs(userName);
for (String url : permissionUrls) {
// 这就表示当前用户有这个权限
if (url.equals(requestURI)) {
hasPermission = true;
break;
}
}
if (hasPermission)
return true;
else {
UnauthorizedException ex = new UnauthorizedException("当前用户没有访问路径 " + requestURI + " 的权限");
subject.getSession().setAttribute("ex", ex);
WebUtils.issueRedirect(request, response, "/unauthorized");
return false;
}
}
}
}
后台代码执行步骤:
- 进入登录界面,该界面在配置文件中配置到:不需任何权限可访问
- 登录,登录方法中有:subject.login(token);
- 执行DatabaseRealm中的doGetAuthenticationInfo校验账号密码
- 如果校验成功,跳转,失败返回登录界面
- 点击页面任一链接。URLPathMatchingFilter执行PermissionServiceImpl中的needInterceptor
- 如果没规定要有权限要求,调整,如果有
- 执行PermissionServiceImpl中的listPermissionURLs,查看使用者的权限
- 有该权限,放行,没有则拦截。