1、Shiro 是什么
Shiro 是一个功能强大和易于使用的Java安全框架。
Shiro 为开发人员提供一个直观而全面的解决方案:认证、授权、加密、会话管理、Web集成、缓存等。
Apache Shiro 和 Spring Security 是同类型的框架,主要用来做安全,也就是我们俗称的权限校验(控制),Shiro 扩展更简单和灵活。
2、Shiro 能干什么
shiro 四个主要的功能
shiro 的其它几个特点
3、shiro 架构
从图中我们可以看到不管是任何请求都会经过 SecurityManager 拦截并进行相应的处理,shiro 几乎所有的功能都是由 SecurityManager 来管理。
其中:
SSM整合看我另一篇文章:https://blog.csdn.net/qq_42402854/article/details/84331025
1、在 maven 项目中引入 Shiro 依赖:
org.apache.shiro
shiro-all
1.3.2
net.sf.ehcache
ehcache
2.10.6
2、在 web.xml 中配置 Shiro 的拦截器:
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
shiroFilter
/*
3、在 spring.xml 中配置 Shiro 的核心组件和拦截规则:
1)核心组件,并配置缓存和自己实现的Realm
public class ShiroRealm extends AuthenticatingRealm{ ... } 后面6有写(Realm 接口 有很多实现类)
2)Shiro 拦截规则:
/login = anon
/logout = logout
/admin/** = authc
/**= anon
4、在 springmvc.xml 中配置 Shiro 的注释:
使用 shiro 注解一般在 controller 中
5、LoginController 实现 访问控制:
登录 index.jsp 页面,访问 url 可以是 项目根路径(主要是注销是自动返回web根目录),也可以是 /login
1)获取到shiro的认证核心组件Subject接口的对象(这个对象封装了登录用户对象信息),并调用Subjent接口的实现对象的login方法来验证用户名和密码,
2)注意:Subjent接口的实现对象的 login 方法,实质上是将参数 token(含有登录用户对象信息)传到我们自定义的ShiroRealm 类中的实现方法里处理
@Controller
public class LoginController {
@GetMapping(value= {"/","/login"})
public String login() {
return "login";
}
@PostMapping("/login")
public String login(User user) {
//使用 shiro 登录验证
//1 认证的核心组件:获取 Subject 对象
Subject subject = SecurityUtils.getSubject();
//2 将登陆表单封装成 token 对象
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPazzword());
try {
//3 让 shiro 框架进行登录验证:
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
return "loginError";
}
return "redirect:/admin/index";
}
@GetMapping("/admin/index")
public String admin(Model model) {
System.out.println("admin");
return "admin/index";
}
}
和 Shiro 拦截规则 的跳转 url 保持一致,jsp页面简单写了几个字
6、自定义 ShiroRealm 实现:
如果实现 Realm 接口,参数 token 会被传递到 supports 方法上
shiro 框架做了一些现成的Realm接口的实现类,比如AuthenticingRealm类等
简单登录认证我们 继承 AuthenticatingRealm 类,参数 token 会被传递到 doGetAuthenticationInfo 方法上
public class ShiroRealm extends AuthenticatingRealm{
@Autowired
private UserMapper userMapper;
/**
* 登录的验证实现方法
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken token2 = (UsernamePasswordToken) token;
String username = token2.getUsername();
User user = userMapper.getUserByUsername(username);
if(user == null) {
throw new UnknownAccountException("用户名或密码有误!");
}
if(user.getStatus() == 0) {
throw new UnknownAccountException("用户名已被禁用,请联系系统管理员!");
}
/**
* principals: 可以使用户名,或d登录用户的对象
* hashedCredentials: 从数据库中获取的密码
* credentialsSalt:密码加密的盐值
* RealmName: 类名(ShiroRealm)
*/
AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPazzword(), null, getName());
return info; //框架完成验证
}
}
7、退出登录
简单写了一个超链接, shiro 拦截规则,退出登陆后自动返回 web 根目录( / 访问登录页面5)
注销
问题:
1)对于 二中 5、6步 为什么调用 subject.login(token); 会执行自定义 Realm 的实现方法?
2)return info; 框架如何完成验证?
1、问题一:
1)表单提交后进入login方法后 调用 subject.login(token);
2)Subject 是通过 securityManager 调用 login() 方法 来进行登录操作
3) DefaultSecurityManager 类
该方法里会验证登录信息,如果登录通过会返回登录信息,如不通过则抛出异常;authenticate 方法定义在父类AuthenticatingSecurityManager 中;
4)AuthenticatingSecurityManager 类
5)AbstractAuthenticator 类
6)ModularRealmAuthenticator 类
4、5 的 authenticate 方法 都交给了 这个类的 doAuthenticate 方法执行,
在这里,终于见到 Realm。这个方法就是在判断程序中定义了几个realm,分别都单个realm和多个realm的处理方法。
我们是单个realm的处理方法 doSingleRealmAuthentication;
7)ModularRealmAuthenticator 类
红色标记部分,就是真正的调用Reaml来实现登录,点进去
8)AuthenticatingRealm 类
第一个标记是从缓存中查看,该用户是否已经登录。如果已经登录怎么直接完成了登录流程;
第二个标记是根据用户信息,去获取数据库保存的该用户的密码等信息;
第三个标记是利用第二个标记得到的数据库该用户的信息和本次登录该用户的信息经行比较,如果正确则验证通过,返回用户信息。如果不通过则验证失败,登录不成功,抛出错误
2、问题二:
简单点分析:
在 UsernamePasswordToken 类的 方法打断点
在 SimpleCredentialsMatcher 类 打断点:
注意:
shiro进行对比密码的是一个接口:CredentialsMatcher
此接口的实现类:
SimpleCredentialsMatcher:没有对密码进行加密,
HashedCredentialsMatcher: 实现了对密码的加密
返回结果后,如果密码对比正确,跳转到登录成功后的页面,密码对比不正确,抛出异常:IncorrectCredentialsException
到此,整合与简单登录认证结束
参考文章:
https://www.jianshu.com/p/a956006bceee
shiro登录步骤源码分析