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

该系统把所有登录验证还有权限控制的工作都交给了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 IO系统--字符流

    字符流:尽管字节流提供了处理任何类型输入/输出操作的足够功能,它们补鞥呢直接操作Unicode字符.字符流层次结构的顶层是Reader和Writer抽象类.类似于InputStream和OutputS ...

  2. 新一代互联网传输协议QUIC

    QUIC(Quick UDP Internet Connections,快速UDP互联网连接)是Google提出的一种基于UDP改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验. Q ...

  3. 008 BOM

    一:说明 1.说明 浏览器对象模型 2.顶级对象 浏览器中的顶级对象是window 页面中的顶级对象是document 因此: 变量属于window的,函数也是window的. 就可以使用window ...

  4. Andorid SQLite数据库开发基础教程(3)

    Andorid SQLite数据库开发基础教程(3) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库. 使用 ...

  5. [原][OE][官方例子]osgearth_features OE地球添加shp文件(特征标识)

    OE所有官方样例 官方示例代码 /* -*-c++-*- */ /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph * Co ...

  6. ES6深入浅出-11 ES6新增的API(上)-2.Array新增API

    Array.form 把不是数组的东西变成数组.最常见的就是把伪数组变成数组 那么什么是伪数组 这就是伪数组,因为它不是继承自Array的原型的对象.它只是一个看起来很像数组的数组 只看下面的代码.a ...

  7. NativeExcel3使用示例

    除了XLSReadWriteII5,还有个NativeExcel也是比较好的操作excel的组件,现将NativeExcel3的使用示例写一下,以下是代码和生成的excel表格的效果: procedu ...

  8. JS和vue文本框输入改变p标签的内容测试

    文本框输入,p标签的内容自动变成文本框的内容,如下是三种方法的测试: 方法1:JS里的onchange,当文本框内容改变事件,该事件里写的方法是,获取p标签本身,然后获取文本框的值,赋值给变量,最后给 ...

  9. 【redis】 windows 32x 64x

    下载地址:http://files.cnblogs.com/files/dtdxrk/redis_win.zip

  10. kubectl exec 执行 容器命令

    格式如下: kubectl exec -it podName -c containerName -n namespace -- shell comand 1 创建目录 kubectl exec -it ...