一、现存问题
1. 认证(登录):认证操作流程都差不多,但是每次都需要手动的基于业务代码去实现,很麻烦!
2. 授权:如果权限控制粒度比较粗,可以自身去实现,但是如果控制粒度比较细,操作麻烦!
3. 分布式会话管理:单体项目时,需要依赖Web容器的Session实现会话,搭建了集群或者是分布式项目,手动去基于Redis或者其他拥有公共存储能力的中间件实现分布式会话管理。
4. 单点登录:在一处服务认证,所有其他服务都信任。
 
二、shiro框架介绍

1. Shiro是基于Java语言编写的,Shiro最核心的功能就是认证和授权
 
2.1 shiro的基本使用
认证流程:
 
 授权流程:
 
2.2 基于内存的方式使用
@Test
public void authen() {
    //认证的发起者(subject),   SecurityManager,   Realm
    //1. 准备Realm(基于内存存储用户信息)
    SimpleAccountRealm realm = new SimpleAccountRealm();
    realm.addAccount("admin", "admin", "超级管理员", "商家");
    //2. 准备SecurityManager
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    //3. SecurityManager和Realm建立连接
    securityManager.setRealm(realm);
    //4. subject和SecurityManager建立联系
    SecurityUtils.setSecurityManager(securityManager);
    //5. 声明subject
    Subject subject = SecurityUtils.getSubject();
    //6. 发起认证
    subject.login(new UsernamePasswordToken("admin", "admin"));
    // 如果认证时,用户名错误,抛出:org.apache.shiro.authc.UnknownAccountException异常
    // 如果认证时,密码错误,抛出:org.apache.shiro.authc.IncorrectCredentialsException:
    //7. 判断是否认证成功
    System.out.println(subject.isAuthenticated());
    //8. 退出登录后再判断
    //        subject.logout();
    //        System.out.println("logout方法执行后,认证的状态:" + subject.isAuthenticated());
    //9. 授权是在认证成功之后的操作!!!
    // SimpleAccountRealm只支持角色的授权
    System.out.println("是否拥有超级管理员角色:" + subject.hasRole("超级管理员"));
    subject.checkRole("商家");
    // check方法校验角色时,如果没有指定角色,会抛出异常:org.apache.shiro.authz.UnauthorizedException: Subject does not have role [角色信息]
}
 
2.3 基于文件存储的方式IniRealm
基于文件存储用户名,密码,角色等信息
 准备一个.ini文件,存储用户信息,并且IniRealm支持权限校验
[users]
// 格式:username=password,role1,role2
admin=admin,超级管理员,运营
[roles]
// 格式:role1=perm1,perm2
超级管理员=user:add,user:update,user:delete
 
具体实现业务的代码:
@Test
public void authen(){
    //1. 构建IniRealm
    IniRealm realm = new IniRealm("classpath:shiro.ini");
    //2. 构建SecurityManager绑定Realm
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);
    //3. 基于SecurityUtils绑定SecurityManager并声明subject
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();
    //4. 认证操作
    subject.login(new UsernamePasswordToken("admin","admin"));
    //5. 角色校验
    // 超级管理员
    System.out.println(subject.hasRole("超级管理员"));
    subject.checkRole("运营");
    //6. 权限校验
    System.out.println(subject.isPermitted("user:update"));
    // 如果没有响应的权限,就抛出异常:UnauthorizedException: Subject does not have permission [user:select]
    subject.checkPermission("user:delete");
}
 
2.4 JdbcRealm方式
用户认证、授权时推荐的表结构设计,经典五张表
 
@Test
public void authen(){
    //1. 构建IniRealm
    JdbcRealm realm = new JdbcRealm();
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql:///shiro");
    dataSource.setUsername("root");
    dataSource.setPassword("root");
    realm.setDataSource(dataSource);
    realm.setPermissionsLookupEnabled(true);
    //2. 构建SecurityManager绑定Realm
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);
    //3. 基于SecurityUtils绑定SecurityManager并声明subject
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();
    //4. 认证操作
    subject.login(new UsernamePasswordToken("admin","admin"));
    //5. 授权操作(角色)
    System.out.println(subject.hasRole("超级管1理员"));
    //6. 授权操作(权限)
    System.out.println(subject.isPermitted("user:add"));
}
 
DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `permission` varchar(128) NOT NULL,
  `role_name` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES ('1', 'user:add', '超级管理员');
INSERT INTO `roles_permissions` VALUES ('2', 'user:update', '超级管理员');
INSERT INTO `roles_permissions` VALUES ('3', 'user:select', '运营');
-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'admin', 'admin');
-- ----------------------------
-- Table structure for `user_roles`
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(128) NOT NULL,
  `username` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES ('1', '超级管理员', 'admin');
INSERT INTO `user_roles` VALUES ('2', '运营', 'admin');
 



















