1. shiro中的重要概念
要理解shiro,先要理解框架的几个概念:
1) Subject : 代表当前登陆或者访问的用户;
2) Principals :一般指用户名等,唯一表明Subject身份也就是当前用户身份的东西;
3) Credentials :凭证,一般指密码,对当前登陆用户进行验证;
4) Realms: 域,一般是指存储用户信息(用户名,密码,权限,角色)的数据库,也就是保存用户权限等信息的数据源 ;
5) SecurityManager :shiro安全管理的顶级对象。它集合或者说调用所有其它相关组件,负责所有安全和权限相关处理过程,就像一个中央集权政府;
2. shiro的子系统
上面我们说到shiro的主要功能有:认证,授权,加密,session管理等。而每一个主要功能对应于shiro的一个子系统, 下面分别介绍。
3. Authentication认证子系统
认证子系统,就是处理用户登录,验证用户登录。
一般我们new一个UsernamePasswordToken的对象:UsernamePasswordToken token = new UsernamePasswordToken("xxxusername", "xxxpassword"),
然后 subject.login(token)就前去登录。相关代码一般如下:
Authentication 子系统会将password加密,然后使用username和加密之后的password和从Realm(一般是数据库)中根据usename获得的密码进行比较,相同就登录成功,不相同同就登录失败,或者用户名不存在也登录失败。就怎么简单。当然从Realm中根据用户名查找用户的过程是需要我们自己编码实现的。该功能的实现代码如下 。
4. Authorization 授权子系统(访问控制,权限控制)
在需要判断用户是否有某权限或者角色时,代码如下:
我们看到 doGetAuthorizationInfo 方法中使用了 SimpleAuthorizationInfo 类封装 Role 和 Permission.roles 和 stringPermissions 都是 String 类型的 Set, 也就是说,它们都是使用字符串来表示你拥有某个角色或者拥有某个权限的。
1) 两种访问控制方式:
SimpleAuthorizationInfo 封装了角色和权限,其实这也说明了实现“访问控制”两种方式:一是 “ 基于角色的访问控制 ” ;而是“ 基于资源的访问控制 ”。所谓的访问控制, 是指对于某个资源,当前用户是否有访问的权限。基于角色的访问控制是一种比较粗粒度的访问控制方式,只要你具有了某个或某几个角色,那么你就可以访问某资源。而基于资源的访问控制,是判断你针对该资源是否有某权限,有才能访问,粒度更细,你是否有某权限,可以根据你有哪些角色,然后改角色有哪些权限来判断的,当然也可以不引入角色的概念,直接判断你是否拥有某些权限。当然两种访问方式可以单独使用,也可以混合使用。比如对于比较简单的权限控制,你可以仅仅只使用基于角色的访问控制,仅仅引入角色表,不需要权限表都可以。混合使用是指,你可以同时要求用户具有某角色并且具有某些权限,才能访问某资源。所以shiro的权限控制时极其灵活的(当然也可以不引入角色表,仅仅引入权限表)。
2)权限的字符串表示方式
上面说到 角色 和 权限 都是使用字符串来表示的,其实 shiro 提供了一套比较强大有点复杂的权限字符串表示格式(分为:分割的三个部分):“ 资源: *** 作:对象实例ID ” 表示:对那个资源的哪个实例可以进行哪些 *** 作,支持通配符。多个 *** 作需要使用 “,” 逗号分割,而 “*” 放在三个位置上,分别表示:任意资源,任意 *** 作,任意实例。比如:"user:delete:1" 就表示 对user表的id等于1对应的数据或者对象,可以进行删除 *** 作。其实资源表现实现可以是对象,其实最终是对应到数据库表中的记录。再比如:"user:update,delete" 就表示 对user表(的任意实例)进行更新和删除 *** 作。"user:update,delete" 其实就等价于 “user:update,delete:*”所以 shiro 的访问控制可以控制到具体实例,或者说具体哪条数据库记录,也可以在表级别控制。如果省略掉 对象实例ID部分,就是在表级别控制。
3)权限相关表的设计
1>如果对于简单的情况,可以只使用“基于角色的访问控制”粗粒度方式,不涉及到权限,仅仅只通过判断是否有某角色来判断访问控制,那么就只需要增加一个角色表(roles) 和 一个角色(roles)和用户(user)的多对多的一个中间表——用户角色表(user_role)。
2>如果仅仅使用权限来控制访问,那么就可以仅仅只增加一个权限表(priv)和一个用户和权限的多对多的一个中间表——用户权限表(user_priv).
3>如果既要用到角色,又要用到权限(权限根据角色推算出来),那么就要增加:角色表,用户角色表,权限表,角色权限表。
4>其实还有一种情况:就是角色和权限没有关系,那么就可以增加:角色表,用户角色表,权限表,用户权限表。不过这种方式不同符合常规。
其他的 如 Cryptography 加密子系统 和 Session Management会话管理子系统 这里不做介绍。
编码与解码
Shiro 提供了 base64 和 16 进制字符串编码、解码的API 支持,方便一些编码解码 *** 作。Shiro 内部的一些数据的存储、表示都使用了base64 和 16 进制字符串。
1、base64 编码与解码
String str = "admin"
String base64Encoded = Base64. encodeToString (str.getBytes())
String str2 = Base64. decodeToString (base64Encoded)
logger .info(str+"<==="+base64Encoded+"==>"+str2)
2、16 进制字符串编码与解码
String str3 = "test"
String hexEncoded2 = Hex. encodeToString (str3.getBytes())
String str4 = new String(Hex. decode (hexEncoded2.getBytes()))
logger .info(str3+"<==="+hexEncoded2+"==>"+str4)
散列算法加密
散列算法一般用于生成数据的重要信息,是一种不可逆的算法,适合存储密码之类的数据,常见的散列算法如MD5、SHA 等。
[if !supportLists]1、[endif]MD5算法盐值加密
String pswd= "123456"
String salt = "123"
String md5 = new Md5Hash(pswd, salt).toString()
另外散列时还可以指定散列次数,new Md5Hash(pswd, salt, 2).toString(),数字2代表加密次数。
[if !supportLists]2、[endif]SHA256 算法盐值加密
String pswd= "123456"
String salt = "123"
String sha = new Sha256Hash(pswd, salt).toString()
[if !supportLists]3、[endif]SHA1算法盐值加密
String pswd= "123456"
String salt = "123"
String sha = new Sha1Hash(pswd, salt).toString()
4、SHA512算法盐值加密
String pswd = "123456"
String salt = "123"
String sha = new Sha512Hash(pswd, salt).toString()
[if !supportLists]5、[endif]Shiro 还提供了通用的散列SimpleHash
String pswd = "123456"
String salt = "123"
//内部使用MessageDigest
String simpleHash=
new SimpleHash("SHA-1",pswd,salt,4).toString()
Shiro 还提供对称式加密、解密算法的支持
[if !supportLists]1、[endif]AES 算法
//生成key
Key key = aesCipherService.generateNewKey()
String pswd = "123456"
//加密
String encrptText = aesCipherService.encrypt(pswd.getBytes(), key.getEncoded()).toHex()
//解密
String text2 =
new String(aesCipherService.decrypt(Hex. decode (encrptText), key.getEncoded()).getBytes())
logger .info(pswd+"<==="+encrptText+"==>"+text2)
简单模拟用户注册
1、首先使用SHA256算法加密密码明文,UserService层实现。
UserDaoImpl userDaoimpl
public static void main(String[] args) {
String email ="123@qq.com"
String password = "123"
String sha = new Sha256Hash(password, ByteSource.Util. bytes (email)).toString()//使用邮箱作为盐值
User user = new User(4L,"管理员",email,sha, new Date(), new Date(),1)
UserService userService = new UserService()
userService.insert(user)
}
public int insert(User user){
userDaoimpl = new UserDaoImpl()
return userDaoimpl.insert(user)
}
2、Dao插入数据
@Override
public int insert(User record) {
String sql = "insert into u_user(id,nickname,email,pswd,create_time,last_login_time,status) values (?,?,?,?,?,?,?)"
return insert(sql,record.getId(),record.getNickname(),record.getEmail(),record.getPswd(),record.getCreateTime(),record.getLastLoginTime(),record.getStatus())
}
HashedCredentialsMatcher 实现密码验证服务
1、自定义JdbcRealm实现AuthorizingRealm接口,重写doGetAuthenticationInfo(,,,)方法。
[if !supportLists]2、[endif]配置ini文件内容
主要配置HashedCredentialsMatcher实现密码验证服务。
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=SHA-256#加密算法
credentialsMatcher.hashIterations=1#迭代次数
credentialsMatcher.storedCredentialsHexEncoded=true
jdbcRealm=com.shiro.test.JdbcRealm
jdbcRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$jdbcRealm
3、]用邮箱、密码实现登录认证
4、结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)