发表于: 2019-11-12 22:43:40

2 923


一、今天完成的事

1.完成shiro授权

1.在shiroConfig中加入两行代码
//权限不足跳转的页面
       shiroFilterFactoryBean.setUnauthorizedUrl("/noAuthc");
 //设置权限拦截器,当权限为superManager才能访问后台
       filterChainDefinitionMap.put("/student/backDesk","perms[user:superManager]");
2.在自定义Realm类中加入权限认证
 /**
    *  权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。
    * @param principalCollection
    * @return
    */
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       System.out.println("------执行授权逻辑----------");
       SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
       //可能存在多个权限控制,所以用list来接收
       Set<String> stringSet = new HashSet<>();
       //和config中的filterChainDefinitionMap.put("/student/backDesk","perms[user:superManager]");对应
       stringSet.add("user:superManager");
       simpleAuthorizationInfo.setStringPermissions(stringSet);
       return simpleAuthorizationInfo;
   }
3.在controller中加入权限不足跳转的页面url

运行之后的效果

如果权限一致可以访问后台

如果权限不足跳转到权限不足页面

4.加入数据库查询功能,形成动态的授权

首先创建五个表。

创建五个表是为了能够更好的模拟角色管理,每个用户可以对应多个角色,每个角色可以对应多个权限

表一:user表,存放用户信息

create table user (
``id bigint auto_increment,
``name varchar(100),
``password varchar(100),
``constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB;

表二:role表,存放角色

create table role (
``id bigint auto_increment,
``name varchar(100),
``constraint pk_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;

表三:permission表,存放权限

create table permission (
``id bigint auto_increment,
``name varchar(100),
``constraint pk_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;

表四:user_role的id联表,用于用户和角色联表查询

create table user_role (
``uid bigint,
``rid bigint,
``constraint pk_users_roles primary key(uid, rid)
) charset=utf8 ENGINE=InnoDB;

表五:role_permission的id联表,用于角色和权限联表查询

create table role_permission (
``rid bigint,
``pid bigint,
``constraint pk_roles_permissions primary key(rid, pid)
) charset=utf8 ENGINE=InnoDB;

在程序中新加两个实体类Role,Permission

public class Role implements Serializable {
   private long id;
   private String name;

   public long getId() {
       return id;
   }

   public void setId(long id) {
       this.id = id;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   @Override
   public String toString() {
       return "Role{" +
               "id=" + id +
               ", name='" + name + '\'' +
               '}';
   }
}
public class Permission {
   private long id;
   private String name;

   public long getId() {
       return id;
   }

   public void setId(long id) {
       this.id = id;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   @Override
   public String toString() {
       return "Permission{" +
               "id=" + id +
               ", name='" + name + '\'' +
               '}';
   }
}

然后编写RoleAndPermissionMapper

@Mapper
public interface RoleAndPermissionMapper {

   /**
    * 获取密码
    * @param name
    * @return
    */
   @Select("select password from user where name=#{name}")
   String getPassword(String name);

   /**
    *联表查询用户对应的角色
    * @param name
    * @return
    */
   @Select("select role.name from user \n" +
           "LEFT JOIN user_role on `user`.id=user_role.uid\n" +
           "LEFT JOIN role on role.id=user_role.rid\n" +
           "where `user`.name=#{name}")
   Set<String> listRoles(String name);

   /**
    * 联表查询用户对应的权限
    * @param name
    * @return
    */
   @Select("select permission.name from user \n" +
           "LEFT JOIN user_role on `user`.id=user_role.uid\n" +
           "LEFT JOIN role on role.id=user_role.rid\n" +
           "LEFT JOIN role_permission on role.id=role_permission.rid \n" +
           "LEFT JOIN permission on permission.id=role_permission.pid \n" +
           "where `user`.name=#{name}")
   Set<String> listPermissions(String name);

   @Insert("insert into user_role(uid,rid) values((select id from user_role where name=#{name}),rid=#{rid})")
   boolean insert(String name,long id);
}

改编CustomRealm

  @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       System.out.println("------执行授权逻辑----------");
       String username = (StringSecurityUtils.getSubject().getPrincipal();
       log.info(username);
       //查询数据库获取权限和角色
       Set<String> permissions = roleAndPermissionService.listPermissions(username);
       Set<String> roles = roleAndPermissionService.listRoles(username);
       log.info(permissions);
       log.info(roles);
       SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
       //设置到shiro中,让shiro来管理
       simpleAuthorizationInfo.setStringPermissions(permissions);
       simpleAuthorizationInfo.setRoles(roles);
       return simpleAuthorizationInfo;
   }

在shiroConfig中修改权限

 filterChainDefinitionMap.put("/student/backDesk","authc,perms[/student/backDesk]");

所以只有权限为“/student/backDesk”才能访问到后台管理页面

运行后的效果

后台日志可以看到权限

前台可以看到正常进入

切换另一个账号

可以看到权限只有update,只能操作update,后台就不能进入

前台页面就会显示

5.加入密码加密功能

在shiroConfig中加入两段代码

/**
    * 加入加密配置
    * @return
    */
   @Bean(name = "credentialsMatcher")
   public HashedCredentialsMatcher hashedCredentialsMatcher() {
       HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
       // 散列算法:这里使用MD5算法;
       hashedCredentialsMatcher.setHashAlgorithmName("md5");
       // 散列的次数,比如散列两次,相当于 md5(md5(""));
       hashedCredentialsMatcher.setHashIterations(2);
       // storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
       hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
       return hashedCredentialsMatcher;
   }

   /**
    * 创建Realm以便调用
    * @return
    */
   @Bean
   public CustomRealm customRealm() {
       CustomRealm customRealm = new CustomRealm();
       // 告诉realm,使用credentialsMatcher加密算法类来验证密文
       customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
       customRealm.setCachingEnabled(false);
       return customRealm;
   }

在controller中加入登录验证

@RequestMapping("/register/0")
   public String toAddUser(){
       return "register";
   }


   @RequestMapping("/register/1")
   public String addUser(User user){
       String pwd = user.getPassword() ;
       String username = user.getName();
       String password = new SimpleHash("MD5"pwd,
               ByteSource.Util.bytes(username + "salt"), 2).toHex();
       user.setPassword(password);
        userService.insert(user);
       return "redirect/login";
   }

修改CustomRealm

 pwd = new SimpleHash("MD5"pwd,
               ByteSource.Util.bytes(username + "salt"), 2).toHex();
       log.info(pwd);
       if (user == null) {
           throw new AuthenticationException("用户名错误");
       }else if(!user.getPassword().equals(pwd)){
           log.info("执行了吗");
           throw new AuthenticationException("密码错误");
       }
       log.info("还在运行?");
       SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(usernameuser.getPassword(),getName());
       return a;

二、遇到的问题

登录验证的时候出现了问题,token验证不成功,报错没解决

三、收获

授权管理的时候需要一起查询角色和权限,学习了spl的联表查询和联表插入

联表插入

insert into user_role(uid,ridvalues((select id from user where name='dada'),1);

联表查询

"select permission.name from user \n" +
           "LEFT JOIN user_role on `user`.id=user_role.uid\n" +
           "LEFT JOIN role on role.id=user_role.rid\n" +
           "LEFT JOIN role_permission on role.id=role_permission.rid \n" +
           "LEFT JOIN permission on permission.id=role_permission.pid \n" +
           "where `user`.name=#{nme}"

四、明天的计划

先解决bug




返回列表 返回列表
评论

    分享到