且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

springboot集成shiro的实体

更新时间:2022-08-12 16:14:08

3.身份认证

在认证、授权内部实现机制中都有提到,最终处理都将交给Real进行处理。因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO.

认证实现

Shiro的认证过程最终会交由Realm执行,这时会调用RealmgetAuthenticationInfo(token)方法。
该方法主要执行以下操作:
1、检查提交的进行认证的令牌信息
2、根据令牌信息从数据源(通常为数据库)中获取用户信息
3、对用户信息进行匹配验证。
4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
5、验证失败则抛出AuthenticationException异常信息。
而在我们的应用程序中要做的就是自定义一个Realm类,继承AuthorizingRealm抽象类,重载doGetAuthenticationInfo (),重写获取用户信息的方法。

既然需要进行身份权限控制,那么少不了创建用户实体类,权限实体类。

在权限管理系统中,有这么几个角色很重要,这个要是不清楚的话,那么就很难理解,我们为什么这么编码了。
第一是用户表:在用户表中保存了用户的基本信息,账号、密码、姓名,性别等;
第二是:权限表(资源+控制权限):这个表中主要是保存了用户的URL地址,权限信息;
第三就是角色表:在这个表重要保存了系统存在的角色;
第四就是关联表:用户-角色管理表(用户在系统中都有什么角色,比如admin,vip等),
第五就是角色-权限关联表(每个角色都有什么权限可以进行操作)。依据这个理论,我们进行来进行编码,很明显的我们第一步就是要进行实体类的创建。在这里我们使用Mysql和JPA进行操作数据库。

引入mysql和JPA的依赖。JPA版本(Mar 03, 2017),mysql版本默认,可以自己选择版本

<!-- Spirng data JPA依赖; -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>1.5.2.RELEASE</version>
</dependency>
<!-- mysql驱动; -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

application.yml配置mysql数据库和JPA

spring:
    datasource:
      url: jdbc:mysql://localhost:3306/数据库名称
      username: mysql的登录帐号
      password: mysql的登录密码
      driver-class-name: com.mysql.jdbc.Driver
    jpa:
      database: mysql
      show-sql: true
      hibernate:
        ddl-auto: update
        naming:
          strategy: org.hibernate.cfg.DefaultComponentSafeNamingStrategy
      properties:
         hibernate:
            dialect: org.hibernate.dialect.MySQL5Dialect

JPA强大之处在于可以自动建表,只要在实体类中用好注解
UserInfoSysRoleSysPermission至于之前的关联表我们使用JPA进行自动生成。

UserInfo用户信息实体类
@Entity声明为实体类
@Id``@GeneratedValue说Id是个自增主键,映射到你这个类中的Integer uid
@Column(unique =true)是指username这个字段的值在这张表里不能重复,所有记录值都要唯一,就像主键那样
@ManyToMany(fetch=FetchType.EAGER)不写默认为LAZY
如果是EAGER,那么表示取出这条数据时,它关联的数据也同时取出放入内存中.
如果是LAZY,那么取出这条数据时,它关联的数据并不取出来
表关联@JoinTable name属性为连接两个表的表名称。若不指定,则使用默认的表名称,格式:"表名1" + "_" + "表名2"(JPA会为我们新建这个表)
joinColumn属性表示,在保存关系的表中,所保存关联关系的外键的字段,并配合@JoinColumn标记使用;
inverseJoinColumn属性与joinColumn类似,它保存的是保存关系的另外一个外键字段;

@Entity
public class UserInfo implements Serializable{
    @Id@GeneratedValue
    private Integer uid;
    @Column(unique =true)
    private String username;//帐号
    private String name;//名称(昵称或者真实姓名,不同系统不同定义)
    private String password; //密码;
    private String salt;//加密密码的盐
    private byte state;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.
    @ManyToMany(fetch=FetchType.EAGER)//立即从数据库中进行加载数据;
    @JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "roleId") })
    private List<SysRole> roleList;// 一个用户具有多个角色
    set和get方法....
    /**
     * 密码盐.
     * @return
     */
    public String getCredentialsSalt(){
        return this.username+this.salt;
    }
//重新对盐重新进行了定义,用户名+salt,这样就更加不容易被破解
}

SysRole系统角色实体类

@Entity
public class SysRole {
    @Id@GeneratedValue
    private Integer id; // 编号
    private String role; // 角色标识程序中判断使用,如"admin",这个是唯一的:
    private String description; // 角色描述,UI界面显示使用
    private Boolean available = Boolean.FALSE; // 是否可用,如果不可用将不会添加给用户

    //角色 -- 权限关系:多对多关系;
    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="permissionId")})
    private List<SysPermission> permissions;

    // 用户 - 角色关系定义;
    @ManyToMany
    @JoinTable(name="SysUserRole",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="uid")})
    private List<UserInfo> userInfos;// 一个角色对应多个用户
    set和get方法....
}

SysPermission权限实体类
@Column(columnDefinition="enum('menu','button')")``columnDefinition属性表示创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用。
例如
columnDefinition属性的特殊使用:
编程语言中字符串一般都用String表示,但是数据库中varcahr数值类型有长度限制,一旦需要大文本,则需要text数值类型
但是String类型默认映射的数值类型是varcharcolumnDefinition可以进行额外指定
@Column(name = "Remark",columnDefinition="text") private String remark;

这里枚举类型enum,resourceType只能是menu或者button,其他都不行
 @Column(columnDefinition="enum('menu','button')")
    private String resourceType;

具体的SysPermission实体类

@Entity
public class SysPermission implements Serializable{
    @Id@GeneratedValue
    private Integer id;//主键.
    private String name;//名称.

    @Column(columnDefinition="enum('menu','button')")
    private String resourceType;//资源类型,[menu|button]
    private String url;//资源路径.
    private String permission; //权限字符串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view
    private Long parentId; //父编号
    private String parentIds; //父编号列表
    private Boolean available = Boolean.FALSE;

    @ManyToMany
    @JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="permissionId")},inverseJoinColumns={@JoinColumn(name="roleId")})
    private List<SysRole> roles;
    set和get方法....
}

到这里实体类就编码完毕了,在这里我们看到的是3个实体类:UserInfo,SysRole,SysPermission
对应的是数据库的五张表:
UserInfo
SysUserRole
SysRole
SysRolePermission
SysPermission
(只需要跑一下程序就会开始创建表)

创建完表之后要输入下数据

INSERT INTO `sys_permission` VALUES ('1', '�', '用户管理', '0', '0/', 'userInfo:view', 'menu', 'userInfo/userList');
INSERT INTO `sys_permission` VALUES ('2', '�', '用户添加', '1', '0/1', 'userInfo:add', 'button', 'userInfo/userAdd');
INSERT INTO `sys_permission` VALUES ('3', '�', '用户删除', '1', '0/1', 'userInfo:del', 'button', 'userInfo/userDel');
INSERT INTO `sys_role` VALUES ('1', '�', '管理员', 'admin');
INSERT INTO `sys_role` VALUES ('2', '�', 'VIP会员', 'vip');
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` VALUES ('1', '2');
INSERT INTO `sys_role_permission` VALUES ('1', '3');
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `user_info` VALUES ('1', 'admin', '管理员', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', '0');

下一篇文章将讲实现身份认证,权限控制

文章主要参考于作者林祥纤的博客

http://412887952-qq-com.iteye.com/blog/2299777