- 概念: Apache Shiro 是一个强大且易用的 Java 安全框架
- 能做什么:Shiro可以帮我们完成 :认证、授权、加密、会话管理、与 Web 集成、缓存等。
主要认识:
- Subject(用户):
当前的操作用户 获取当前用户Subject currentUser = SecurityUtils.getSubject()
- SecurityManager(安全管理器):
Shiro的核心,负责与其他组件进行交互,实现 subject 委托的各种功能
- Realms(数据源) :
Realm会查找相关数据源,充当与安全管理间的桥梁,经过Realm找到数据源进行认 证,授权等操作
- Authenticator(认证器):
用于认证,从 Realm 数据源取得数据之后进行执行认证流程处理。
- Authorizer(授权器):
用户访问控制授权,决定用户是否拥有执行指定操作的权限。
- SessionManager (会话管理器): 支持会话管理
- CacheManager (缓存管理器): 用于缓存认证授权信息
- Cryptography(加密组件): 提供了加密解密的工具包
认证的关键对象:
Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体Principal:身份信息
身份信息,是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)credential:凭证信息
凭证信息,是只有主体自己知道的安全信息,如密码、证书等认证流程
将用户(主体)的用户名(身份信息)和密码(凭证信息)封装成Token(令牌)对象给到安全管理器进行校验 ```xmlorg.apache.shiro shiro-core 1.5.3
<a name="vgEHU"></a>
##### 常见的异常类型
- DisabledAccountException(帐号被禁用)
- LockedAccountException(帐号被锁定)
- ExcessiveAttemptsException(登录失败次数过多)
- ExpiredCredentialsException(凭证过期)等
<a name="WsqgG"></a>
### 认证代码
```java
//1.创建安全管理器对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//2.给安全管理器设置realm
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//3.SecurityUtils给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//4.关键对象subject主体
Subject subject = SecurityUtils.getSubject();
//5.创建令牌
UsernamePasswordToken token = new UsernamePasswordToken("zax","123456");
try {
System.out.println("认证状态"+subject.isAuthenticated());//fasle
//用户认证
subject.login(token);
System.out.println("认证状态"+subject.isAuthenticated());
}catch (UnknownAccountException e){
e.printStackTrace();
System.out.println("认证失败,用户名不存在");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("认证失败,密码错误");
}
SimpleAccountRealm的部分源码中有两个方法一个是 认证 一个是 授权
MD5+salt+hash散列
//使用md5
Md5Hash md5Hash = new Md5Hash("123");
System.out.println(md5Hash.toHex());
//使用MD5 + salt处理
Md5Hash md5Hash1 = new Md5Hash("123", "X0*7ps");
System.out.println(md5Hash1.toHex());
//使用md5 + salt + hash散列(参数代表要散列多少次,一般是 1024或2048)
Md5Hash md5Hash2 = new Md5Hash("123", "X0*7ps", 1024);
System.out.println(md5Hash2.toHex());
自定义Realm类
package com.kgc.dmeo.test;
import com.kgc.dmeo.entity.User;
import com.kgc.dmeo.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 自定义Realm
*/
@Component
public class CustomerRealm extends AuthorizingRealm {
@Autowired(required = false)
private UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取 token中的 用户名
String principal = (String) token.getPrincipal();
//假设这是从数据库查询到的信息
// String username="zhangsan";
// String password="7268f6d32ec8d6f4c305ae92395b00e8";//加密后
User user = userService.getUserById(principal);
//根据用户名查询数据库
// username.equals(principal)
if (user!=null) {
//参数1:数据库用户名
//参数2:数据库md5+salt之后的密码
//参数3:注册时的随机盐
//参数4:realm的名字
return new SimpleAuthenticationInfo(principal,
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
this.getName());
}
return null;
}
}
//1.创建安全管理器
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//2.注入realm
CustomerRealm realm = SpringUtil.getBean(CustomerRealm.class);
//3.设置realm使用hash凭证匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//声明:使用的算法
credentialsMatcher.setHashAlgorithmName("md5");
//声明:散列次数
credentialsMatcher.setHashIterations(1024);
//设置凭证匹配器
realm.setCredentialsMatcher(credentialsMatcher);
//将realm放入安全管理器中
defaultSecurityManager.setRealm(realm);
//4.将安全管理器注入安全工具
SecurityUtils.setSecurityManager(defaultSecurityManager);
//5.通过安全工具类获取subject
Subject subject = SecurityUtils.getSubject();
//6.认证
UsernamePasswordToken token = new UsernamePasswordToken("12121", "123");
try {
subject.login(token);
System.out.println("登录成功");
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误");
}
授权
授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。
授权方式
shiro提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限: