这两天接手了下师兄的项目,要给系统加个日志管理模块,其中需要记录登录功能的日志,那么首先要知道系统的登录是在哪里实现验证的。

该系统把所有登录验证还有权限控制的工作都交给了shiro。

这篇文章就先简单记录下这两天看的关于shiro登录验证的小总结。

(本文是看了一天代码和博客总结出的大概理解,有点模糊还可能不一定对……有大佬知道哪里错的话希望能评论指出下哈哈哈)

主要就一直在解决几个问题:

1. 怎么验证身份?

首先理解几个概念,token是用户提交的东西,一般有两部分Principal(账号或者用户名)和Credentials(密码或者验证的东西)。

然后Subject很重要,可以看作是验证用户或者用户的一个抽象。

然后有个AuthenticationInfo,这个可以理解成是正确的用户验证信息的一个抽象吧。验证主要就是重写一个方法:

 /*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
//获取用户的输入的账号.
String name = (String)token.getPrincipal();
// System.out.println("token---------++++++++---------->"+(String)token.getPrincipal()+(String)token.getCredentials());
//通过name从数据库中查找 User对象,如果找到,没找到.
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
Map<String, Object> map= new HashMap<String, Object>();
map.put("uName", name);
User user = securityShiroService.selectByUserInfo(map); if(user == null){
return null;
}
//System.out.println("token---------++++++++---------->"+user.getuName()+user.getId());
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user, //用户名
user.getuPass(), //密码
ByteSource.Util.bytes(user.getuName()+"jintu"),//salt=username+salt
getName() //realm name
); // 当验证都通过后,把用户信息放在session里
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute("userInfo", user);
return authenticationInfo;
}

然后看这里的代码我很不解——这里就根据用户提交的token的name也就用户名,然后去数据库里面找到用户的具体信息,然后就把信息保存在session中???

exm??不用对比密码对不对的吗??

然后看了这篇博客:https://www.jianshu.com/p/1a371f3cec27

他说   查看shiro源码才知道:

大概就是首先在进入自定义Realm之前,会经过AuthenticatingRealm这个类的getAuthenticationInfo方法,在这个方法里面会用到你的authenticationInfo然后和token进行比较,然后判断是不是验证成功,也就是说,你在这个重写的realm方法中给出正确的用户信息后,登录验证这个东西交给shiro去做了。

嗯应该这样理解吧。

2. 师兄代码里面并没有currentUser.login(token)???

我看网上的demo基本都是在控制器里面,拦截登录请求,然后调用这个login(token)语句,怎么项目里面找不到呢????

这个我看了这篇文章大概理解了下:https://www.jianshu.com/p/0662cf366161

首先,shiro会有个过滤器filter,你可以配置哪些资源需要拦截然后通过验证才能访问,哪些资源不用验证可以直接访问。

一般会有几个属性设置:

filter里面是可以放行的资源;然后logout显然就和退出登录有关,大概就是退出登录的请求吧;authc=/**意味着所有资源都要经过验证除了前面放行的;loginUrl就是登录请求的路径咯,然后两个很显然了,shiro判断你登录成功后跳转的界面还有最后一个应该是没有权限后显示的界面。

根据上面那个博客,大概可以猜到,系统没有开放login界面,因此我们访问login界面也好其他系统界面也好,首先就会要验证,要验证shiro就会启动他那套验证,内部调用我们重写的doGetAuthenticationInfo然后完成验证工作。

所以大概梳理了下系统可能的登录验证逻辑

首先是网关处controller的代码:

@Controller
public class HomeController { private final static Logger logger = Logger.getLogger(HomeController.class); @RequestMapping({ "/", "/index" })
public String index(ModelMap model,HttpServletResponse resp) { Session session = SecurityUtils.getSubject().getSession();
User user = (User) session.getAttribute("userInfo");
Cookie cookie = new Cookie("sssid", user.getId());
cookie.setMaxAge(7200);
resp.addCookie(cookie);
Cookie cookies = new Cookie("zytypes", String.valueOf(user.getuType()));
cookies.setMaxAge(7200);
resp.addCookie(cookies);
return "redirect:/gate-ui/index"; } @RequestMapping("/login")
//public ModelAndView login(HttpServletRequest request,Model model) throws Exception {
public String login( HttpServletRequest request,Model model) throws Exception {
//进入登录页面时,清空数据
Subject subject = SecurityUtils.getSubject(); subject.logout();
// 登录失败从request中获取shiro处理的异常信息,shiroLoginFailure:就是shiro异常类的全类名.
String exception = (String) request.getAttribute("shiroLoginFailure");
logger.info("登录异常 -- > " + exception);
String msg = "";
if (exception != null) {
if (UnknownAccountException.class.getName().equals(exception)) {
logger.info("UnknownAccountException -- > 账号不存在!");
msg = "账号不存在!";
} else if (IncorrectCredentialsException.class.getName().equals(exception)) {
logger.info("IncorrectCredentialsException -- > 密码不正确!");
msg = "密码不正确!";
} else if ("kaptchaValidateFailed".equals(exception)) {
logger.info("kaptchaValidateFailed -- > 验证码错误!");
msg = "验证码错误!";
} else {
msg = "else >> " + exception;
logger.info("else -- >" + exception);
}
}
model.addAttribute("msg",msg);
// 此方法不处理登录成功,由shiro进行处理
// return new ModelAndView("/login");
return "login";
} @RequestMapping("/403")
public String unauthorizedRole() {
return "403";
}
}

这个代码我看的真的很懵一开始……为什么login那个controller完全没有登录业务?????而是在处理登录失败的信息????

现在大概梳理下:首先,我们输入url的时候不管是不是login的请求,就不管是不是/login,都是会被shiro的filter拦截,然后就要验证嘛。

因为我们设定了登录地址:

所以我猜应该shiro一旦需要验证你身份了,就会跳到这个界面。所以应该出现这个界面的时候,还没经过login的那个controller。

然后你就提交表单请求,有token然后shiro就会根据你的doGetAuthenticationInfo和token对比完成验证,我们不是设置了shiro的successUrl嘛:

那登录失败呢???登录失败应该就是还有验证信息的意思吧,所以应该跳转到/login,所有我们看到homeController里面/login的controller,它第一步是logOut(),这个应该是清除session中存好的用户信息,然后将之前登陆失败的原因从request中拿出来,这个失败的原因应该是shiro在登录失败后会放在request中。

然后将登录失败的信息通过SPringMVC给到前端显示。

为什么要第一步logOut???因为师兄doGetAuthenticationInfo方法的实现里面,根据token的用户名拿到用户信息后,不管三七二十一都会吧信息存到shiro的session中,登录成功的话就session里面有用户信息,登录失败又跳到/login就肯定要先logout()清楚session呗。

附:关于Shiro的session

项目用的是SpringCloud微服务的框架,登录的验证代码是在gate工程中,但在admin工程中我看到一样可以使用shiro的session???、

不应该是不一样的tomcat吗,怎么会一样的session???

后面百度了下,这个session和http中的session是不一样的:

shiro的session好像是基于Java对象的,是和之前理解的不一样。

如上图所示,shiro自己定义了一个新的Session接口,用于统一操作接口,并通过SessionManager实现Session管理。
其中的3个实现类HttpServletSession,SimpleSession和StoppingAwareProxiedSession是我们经常需要打交道的。

然后shiro有个sessionDao的东西,就是可以吧session持久化,然后项目里面看到相关的代码实现好像用了redis,也就是说系统应该是吧session存到redis里了。

还有个不懂的地方

我们来看看这个登录界面login:

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>广东省中药资源动态监测系统</title>
<link rel="stylesheet" type="text/css" href="css/styles.css"/>
</head>
<body>
<div class="htmleaf-container">
<div class="wrapper">
<div class="container">
<h1>广东省中药资源动态监测系统</h1> <form class="form" action="" method="post">
<input type="text" name="username" id="username" autofocus placeholder="Username">
<input type="password" name="password" id="password" placeholder="Password">
<button type="submit" id="login-button">登陆</button>
<input type="checkbox" type="hidden" name="rememberMe" title="记住我" checked="">
<p id="msg" th:text="${msg}"></p>
</form>
</div> <ul class="bg-bubbles">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div> <script src="js/jquery-2.1.1.min.js" type="text/javascript"></script>
</body>
</html>

可以看到,这个页面除了jQuery的js包,没有引入其他的js文件了。

那登录请求是怎么发给服务器的????

而且,暂时在代码中没有找到任何解析登录表单然后转换成shiro相关token的代码……

所以两个疑问:

1. 登录请求怎么发到后端的?

2. 用户请求怎么转换成token的???

我猜测就是指定了shiro登录的界面后,就会将登录界面表单的东西自动封装成token,但网上没能找到相关资料………………

代码也看不到相关配置……和代码,希望哪个大佬知道为什么可以解答我哈哈哈谢谢。

最后还找到了个思路和这个项目差不多的登录验证博客:https://blog.csdn.net/caiqiandu/article/details/88973995

评论了作者我的疑问但到目前还没回复哈哈

写的挺详细的但仍然没有回答我不明白的地方&………………

参考博客:

https://www.jianshu.com/p/1a371f3cec27——《应该在自定义Realm的doGetAuthenticationInfo方法中做什么》——告诉我大概怎这个方法有什么用,一般怎么重写

https://www.jianshu.com/p/0662cf366161——《shiro 登录验证的一个问题》——让我大概知道为什么可以不用调用user.login(token)

两个关于shirosession的:

https://blog.csdn.net/changudeng1992/article/details/81914628——《Shiro笔记四(会话管理):SessionDao》

https://blog.csdn.net/bitree1/article/details/50498970——《org.apache.shiro.SecurityUtils.getSubject().getSession()》

一个常规的登录授权demo——https://blog.csdn.net/qq_33556185/article/details/51579680——《详解登录认证及授权--Shiro系列(一)》

一个和项目基本思路一样的登录验证例子——https://blog.csdn.net/caiqiandu/article/details/88973995——《shiro登陆注册拦截器》

shiro登录验证简单理解的更多相关文章

  1. SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码

    序: 给Shiro加入验证码,有多种方式,当然你也可以通过继承修改FormAuthenticationFilter类,通过Shiro去验证验证码.具体实现请百度: 应用Shiro到Web Applic ...

  2. shiro登录验证原理

    这段时间有点忙,没咋写博客,今天打开staruml看到以前画的一张shiro原理图,先在这发一下,空了再好好进行分析.

  3. VueJs组件prop验证简单理解

    今天看了vuejs的组件,看到了prop组件,主要作用是在传入数据的时候对传入的值做判断,写了个小例子. <div id="app"> <my-child :nu ...

  4. Vue elelment登录验证 简单版

    http.js import axios from 'axios' import { Message, Loading } from 'element-ui'; import router from ...

  5. 简单两步快速实现shiro的配置和使用,包含登录验证、角色验证、权限验证以及shiro登录注销流程(基于spring的方式,使用maven构建)

    前言: shiro因为其简单.可靠.实现方便而成为现在最常用的安全框架,那么这篇文章除了会用简洁明了的方式讲一下基于spring的shiro详细配置和登录注销功能使用之外,也会根据惯例在文章最后总结一 ...

  6. Shiro安全框架入门篇(登录验证实例详解与源码)

    转载自http://blog.csdn.net/u013142781 一.Shiro框架简单介绍 Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权.Shiro在JavaSE和J ...

  7. Apache Shiro:【2】与SpringBoot集成完成登录验证

    Apache Shiro:[2]与SpringBoot集成完成登录验证 官方Shiro文档:http://shiro.apache.org/documentation.html Shiro自定义Rea ...

  8. 【ADO.NET】2、各种版本的 简单登录验证

    一.简单登录验证(防SQL注入) GetString(序号) 返回某一列的值(当用户不记得列名序号时,可使用GetOrdinal()获取到序号)GetInt32(序号) 针对的是 int 字段,返回i ...

  9. 基于权限安全框架Shiro的登录验证功能实现

    目前在企业级项目里做权限安全方面喜欢使用Apache开源的Shiro框架或者Spring框架的子框架Spring Security. Apache Shiro是一个强大且易用的Java安全框架,执行身 ...

随机推荐

  1. Java_jdbc 基础笔记之五 数据库连接 (ResultSet)

    /** * ResultSet: 结果集. 封装了使用 JDBC 进行查询的结果. * 1. 调用 Statement 对象的 executeQuery(sql)可以得到结果集. * 2. Resul ...

  2. 编程基础-c语言中指针、sizeof用法总结

    1.指针 学习 C 语言的指针既简单又有趣.通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的.所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的. ...

  3. 给Oracle字段和表加注释

    给字段加注释 comment on column testtb17.AGE is '年龄';comment on column testtb17.CREATEDTIME is '创建时间';comme ...

  4. MyBatis 示例之存储过程

    存储过程在数据库中比较常见,虽然大多数存储过程比较复杂,但是使用 MyBatis 调用时,用法都一样,因此我们这一节使用一个简单的存储过程来了解 MyBatis 中存储过程的使用方法. 基本准备 存储 ...

  5. 阿里云EDAS功能简介

    尊敬的 EDAS 用户: 您好!为了给您带来更好的服务和使用体验,EDAS 产品团队将对 EDAS 标准版(含按量付费和包年包月)进行一轮调整,包括按量付费标准版价格和免费额度的更新,以及标准版套餐的 ...

  6. 【MySQL】Mac通过brew安装的MySQL重启方法

    问题 在 Mac 上通过 brew install mysql 安装的的MySQL使用基本MySQL命令重启会失败: mysql.server stop mysql.server start mysq ...

  7. 数据包分析中Drop和iDrop的区别

    数据包分析中Drop和iDrop的区别   在数据包分析中,Drop表示因为过滤丢弃的包.为了区分发送和接受环节的过滤丢弃,把Drop又分为iDrop和Drop.其中,iDrop表示接受环节丢弃的包, ...

  8. Kotlin介绍

    Kotlin介绍 转 https://www.jianshu.com/p/d30406daaf25 Google在今年的IO大会上宣布,将Android开发的官方语言更换为Kotlin,作为跟着Goo ...

  9. (待续)【转载】 DeepMind发Nature子刊:通过元强化学习重新理解多巴胺

    原文地址: http://www.dataguru.cn/article-13548-1.html -------------------------------------------------- ...

  10. 查看Oracle中是否有锁表

    转: 查看Oracle中是否有锁表 2018-04-23 17:59 alapha 阅读(19450) 评论(0) 编辑 收藏 一.用dba用户登录,或者将用户赋权为DBA用户 命令: su - or ...