3.身份认证
在认证、授权内部实现机制中都有提到,最终处理都将交给Real进行处理。因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO.
认证实现
Shiro
的认证过程最终会交由Realm
执行,这时会调用Realm
的getAuthenticationInfo(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强大之处在于可以自动建表,只要在实体类中用好注解UserInfo
、SysRole
、SysPermission
至于之前的关联表我们使用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类型默认映射的数值类型是varchar
,columnDefinition
可以进行额外指定@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');
下一篇文章将讲实现身份认证,权限控制