既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
4. shiro中的认证
4.1 认证
身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。
4.2 shiro中认证的关键对象
- Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
- Principal:身份信息
是主体(subject)进行身份认证的标识,标识必须具有唯一性
,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
- credential:凭证信息
是只有主体自己知道的安全信息,如密码、证书等。
4.3 认证流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEb7L6Z6-1680591385485)(Shiro 实战教程.assets/image-20200521204452288.png)]
4.4 认证的开发
1. 创建项目并引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.5.3</version>
</dependency>
2. 引入shiro配置文件并加入如下配置
[users]
mosin=1234
tom=1234
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2zU9GESA-1680591385485)(Shiro 实战教程.assets/image-20220528172213825.png)]
3.开发认证代码
/\*\*
\* @author: mosin
\* @version: v1.0
\*/
public class ShiroTest {
public static void main(String[] args) {
//创建默认的安全管理器
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//创建安全管理器需要的realm对象
IniRealm iniRealm = new IniRealm("classpath:realm.ini");
//安全管理器设置realm对象
defaultSecurityManager.setRealm(iniRealm);
//将安全管理器注入安全工具类 用于获取认证的主体
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取认证的主体
Subject subject = SecurityUtils.getSubject();
//创建令牌
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("mosin", "1234");
try {
//认证 通过没有任何的异常
subject.login(usernamePasswordToken);
//验证是否通过
boolean authenticated = subject.isAuthenticated();
System.out.println("认证通过:"+authenticated);
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误!");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误!");
}
}
}
- DisabledAccountException(帐号被禁用)
- LockedAccountException(帐号被锁定)
- ExcessiveAttemptsException(登录失败次数过多)
- ExpiredCredentialsException(凭证过期)等
4.5 自定义Realm
上边的程序使用的是Shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。
1.shiro提供的Realm
2.根据认证源码认证使用的是SimpleAccountRealm
SimpleAccountRealm的部分源码中有两个方法一个是 认证 一个是 授权
,
public class SimpleAccountRealm extends AuthorizingRealm {
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
SimpleAccount account = getUser(upToken.getUsername());
if (account != null) {
if (account.isLocked()) {
throw new LockedAccountException("Account [" + account + "] is locked.");
}
if (account.isCredentialsExpired()) {
String msg = "The credentials for account [" + account + "] are expired";
throw new ExpiredCredentialsException(msg);
}
}
return account;
}
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = getUsername(principals);
USERS_LOCK.readLock().lock();
try {
return this.users.get(username);
} finally {
USERS_LOCK.readLock().unlock();
}
}
}
3.自定义realm
/\*\*
\* 自定义realm
\*/
public class CustomerRealm extends AuthorizingRealm {
//认证方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
//授权方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String principal = (String) token.getPrincipal();
if("mosin".equals(principal)){
return new SimpleAuthenticationInfo(principal,"123",this.getName());
}
return null;
}
}
4.使用自定义Realm认证
public class TestAuthenticatorCustomerRealm {
public static void main(String[] args) {
//创建securityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//IniRealm realm = new IniRealm("classpath:realm.ini");
//设置为自定义realm获取认证数据
defaultSecurityManager.setRealm(new CustomerRealm());
//将安装工具类中设置默认安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取主体对象
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token = new UsernamePasswordToken("mosin", "1234");
try {
subject.login(token);//用户登录
System.out.println("登录成功");
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误!!");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误!!!");
}
}
}
4.6 使用MD5和Salt
实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shiro完成密码校验。
1.自定义md5+salt的realm
/\*\*
\* 自定义md5+salt realm
\*/
public class CustomerMD5Realm extends AuthorizingRealm {
//授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
//认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String principal = (String) token.getPrincipal();
//根据用户名查询数据库
if("mosin".equals(principal)){
// 参数1:用户名 参数2:密码 参数3:盐 参数4:自定义realm的名字
System.out.println(this.getName());
return new SimpleAuthenticationInfo(principal, "800d63a19662b2ba95bc2ffa01ab4804", ByteSource.Util.bytes("mosin"),this.getName());
}
return null;
}
}
2.使用md5 + salt 认证
public class CustomerMD5RealmTest {
public static void main(String[] args) {
//创建安全管理器
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//创建自定义MD5Realm对象
CustomerMD5Realm customerMD5Realm = new CustomerMD5Realm();
//创建密码认证匹配器对象
HashedCredentialsMatcher md5 = new HashedCredentialsMatcher("MD5");
//设置散列的次数
md5.setHashIterations(1024);
//设置密码认证匹配器对象
customerMD5Realm.setCredentialsMatcher(md5);
//设置安全管理器的 认证安全数据源
defaultSecurityManager.setRealm(customerMD5Realm);
//设置安全工具类的安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取认证的主体
Subject subject = SecurityUtils.getSubject();
//创建令牌
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("mosi", "12345");
//登录认证
try {
subject.login(usernamePasswordToken);
System.out.println("认证通过:"+subject.isAuthenticated());
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误!!!");
}
}
}
5. shiro中的授权
5.1 授权
授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。
5.2 关键对象
授权可简单理解为who对what(which)进行How操作:
Who,即主体(Subject)
,主体需要访问系统中的资源。
What,即资源(Resource)
,如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型
和资源实例
,比如商品信息为资源类型
,类型为t01的商品为资源实例
,编号为001的商品信息也属于资源实例。
How,权限/许可(Permission)
,规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。
5.3 授权流程
5.4 授权方式
-
基于角色的访问控制
- RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制
if(subject.hasRole("admin")){ //操作什么资源 }
-
基于资源的访问控制
- RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制
if(subject.isPermission("user:update:01")){ //资源实例 //对01用户进行修改 } if(subject.isPermission("user:update:\*")){ //资源类型 //对01用户进行修改 }
5.5 权限字符串
权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。
例子:
- 用户创建权限:user:create,或user:create:*
- 用户修改实例001的权限:user:update:001
- 用户实例001的所有权限:user:*:001
5.6 shiro中授权编程实现方式
- 编程式
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
- 注解式
@RequiresRoles("admin")
public void hello() {
//有权限
}
- 标签式
JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
<shiro:hasRole name="admin">
<!— 有权限—>
</shiro:hasRole>
注意: Thymeleaf 中使用shiro需要额外集成!
5.7 开发授权
1.realm的实现
public class CustomerRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String primaryPrincipal = (String) principals.getPrimaryPrincipal();
System.out.println("primaryPrincipal = " + primaryPrincipal);
![img](https://img-blog.csdnimg.cn/img_convert/7a15366d9d8e981ed3265ca3f340c1b9.png)
![img](https://img-blog.csdnimg.cn/img_convert/957a9460facdb49c3e2a4423955477fc.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
ncipals) {
String primaryPrincipal = (String) principals.getPrimaryPrincipal();
System.out.println("primaryPrincipal = " + primaryPrincipal);
[外链图片转存中...(img-eRu8hRvK-1715638745699)]
[外链图片转存中...(img-IHyXOCgm-1715638745700)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**