引 言

 相关内容 : https://blog.csdn.net/superyayaya/article/details/94408805

 在web 中, 不同角色的用户, 具有不同的访问权限, 有的页面可以访问, 有的页面不可以访问, 那么如果不使用任何框架

你如何来解决这个问题? 你可能会建立一个表, 存储着不同用户对应不同的角色, 权限, 然后再每次访问页面的时候, 去查看当

前用户的权限,来判定当前页面他是否可以被访问; 如果在一个页面中有的内容, admin 可以看到, user 看不到, 那么你又会

怎么去做? 你可能会在js 写 一些逻辑判断语句,然显示一些admin 角色下的内容。

一、 什么是shiro

  Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以

快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

二、ssm 框架下 如何使用shiro

  2.1、引入依赖

    <!-- 引入shiro依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.1</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.1</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.4.1</version>
</dependency>

  

  2.2  编写配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 一般是将什么东西如spring 进行整合的时候, 一般就是以bean 的方式 注册到 ioc 容器,已供后面使用 --> <!-- 首先下面是将这个bean注入到 Ioc 容器中, 然后供后面的过滤器使用(这个类实际上已经写好了) -->
<!-- 但是这个类里面的属性需要自己去设置,所以 才有下面的property 这些东西-->
<!-- 想一想之前你是怎么将一个一个类注册到ioc容器中的, 里面依赖的属性可以通过property的方式将他注入-->
<!-- 如果不使用下面的这个property的方法, 那么更方便的是使用autowired 的方式注入-->
<!-- 所以property 相当于 手动注入, autowired 相当于自动注入--> <!-- 下面这个bean 的设置是因为 web.xml 中的DelegatingFilterProxy会自动到Spring Ioc 容器中,寻找name为shiroFilter的bean,
并且将所有Filter的操作都委托给他管理(自己内部源码的机制)--> <!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的安全管理器,所有关于安全的操作都会经过SecurityManager -->
<property name="securityManager" ref="securityManager"/>
<!-- 系统认证提交地址,如果用户退出即session丢失就会访问这个页面 -->
<property name="loginUrl" value="/login.jsp"/>
<!-- 权限验证失败跳转的页面,需要配合Spring的ExceptionHandler异常处理机制使用 -->
<!-- 当用户访问越过权利的url或者 jsp的时候, 用户处于未授权的状态,然后就会跳转到下面的url-->
<!-- 即用户访问了自己没有权利, 访问的页面的时候, 就会跳转到下面的页面里面去-->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name = "filterChainDefinitionMap" ref="filterChainDefinitionMap"/>
<!--<!– <property name="filters">–>-->
<!--<!– <util:map>–>-->
<!--<!– <entry key="authc" value-ref="formAuthenticationFilter"/>–>-->
<!--<!– </util:map>–>-->
<!--<!– </property>–>-->
<!-- <!– 自定义的过滤器链,从上向下执行,一般将`/**`放到最下面 –>-->
<!-- <!– anon : 表示可以匿名访问-->
<!-- authc:表示必须认证后(登录后)才可以访问的页面-->
<!-- logout: 登出的过滤器,用于将登录用户的信息进行销毁\-->
<!-- roles: 权限过滤器,用于对不同 url 和 jsp 页面进行访问权利设置-->
<!-- roles[user] 里面的“user” 就是一个字符串-->
<!-- –>-->
<!-- <property name="filterChainDefinitions">-->
<!-- <!– 下面这个value 这种方式很好吗?-->
<!-- 在很多问题的,权限的时候,可以进行方式的替换-->
<!-- 因为设置就是filterChainDefinitions, 所以可以通过类的方式再进行数据的匹配–>-->
<!-- <value>-->
<!-- /login.jsp = anon-->
<!-- /login = anon-->
<!-- /logout = logout-->
<!-- /user.jsp = roles[user]-->
<!-- /admin.jsp = roles[admin]-->
<!-- /** = authc-->
<!-- </value>-->
<!-- </property>-->
</bean> <!--配置一个bean, 该bean实际上一个Map, 通过实例工厂方法的方式实现的 -->
<bean id = "filterChainDefinitionMap"
factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap">
</bean>
<bean id = "filterChainDefinitionMapBuilder"
class = "com.shiro.factory.FilterChainDefinitionMapBuilder">
</bean> <!-- 安全管理器 -->
<!-- 下面这些属性的设置, 可能直接在DefaultWebSecurityManager类, 里面找不到-->
<!-- 是因为这个类一层一层实现其他类的结果, 所以可能设置是其他的类-->
<!-- 下面的属性 realms 原来是配置在authenticator 的realms 属性的 -->
<!-- 现在是将realms 配置在 securityManager的 realms -->
<!-- 现在内部还是会将realms 设置给 auhthenticator 的 realms 属性里面-->
<!-- 现在从认证上看, 没有什么变化, 但是现在给securityManager 配置 realms 属性 是为后面的授权做准备的 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name = "authenticator" ref = "authenticator"></property>
<property name = "realms">
<list>
<ref bean = "ShiroRealm" />
<ref bean = "SecondRealm" />
</list>
</property>
</bean> <!--因为下面这个类 ModularRealmAuthenticator,这个类里面专门用于对多个realm 操作的验证的方法-->
<!-- 设置属性list, 用于设置 ModularRealmAuthenticator 里面的 collection realms 属性-->
<!-- 默认使用的是AleastOneSuccessfulStrategy
public ModularRealmAuthenticator() {
this.authenticationStrategy = new AtLeastOneSuccessfulStrategy();
}
因为在他的构造方法里面设置了 认证策略
-->
<bean id = "authenticator" class = "org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<property name = "authenticationStrategy" >
<bean class = "org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
</property>
</bean> <!-- 对下面的realm 设置的时候也可以配置相应的缓存
因为在很多权限页面访问时候,需要验证权限的时候,需要每次去调用验证权限的方法
但是在一次会话中,用户的权限是一定的, 所以可以给shiro 设置权限来解决,提高
代码的效率, 但是现在我还不怎么会配置, 可不可以之前像使用redis 缓存一样
直接在方法上面添加缓存的标签吗?
或者又是什么方法?
--> <!-- 第一个Realm实现 -->
<!-- 配置realm 配置 中 对获取前台密码加密方式的的类 -->
<bean id = "SecondRealm" class = "com.shiro.ShiroRealm">
<property name = "credentialsMatcher">
<!-- 配置验证原则 -->
<bean class = "org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value = "1024"></property>
</bean>
</property>
</bean>

<!-- 第二个Realm实现 -->
<!-- 配置realm 配置 中对 密码加密的类 -->
<bean id = "ShiroRealm" class = "com.shiro.SecondRealm">
<property name = "credentialsMatcher">
<bean class = "org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA1"></property>
<property name="hashIterations" value = "1024"></property>
</bean>
</property>
</bean>
</beans>

  

  2.3 编写realm

package com.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
/**
* 现在是使用多个不同的realm 验证
* 因为安全数据可能存放在不同的数据库中,不同的数据会有不同的加密原则
* 所以配置不同加密原则的realm 用于匹配不同的类型的安全数据
*/
public class SecondRealm extends AuthenticatingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// AuthenticationInfo 这是一个接口, 然后实现他的实现类 UsernamePasswordToken upToken = (UsernamePasswordToken) token;
System.out.println("--> SencondRealm"); // 查看token里面username, password 这些参数
String username = upToken.getUsername();
char[] password = upToken.getPassword(); //最开始传入的是字符串,在usernamePassword 里面就进行了char[] 的转化工作 // 如果是不知道的用户, 抛出 异常unknownAccountException 异常
if("unknow".equals(username)){
throw new UnknownAccountException("用户名字不存在");
}
// 如果用户被锁定, 则抛出异常 LockedAccoutException
if("monster".equals(username)){
throw new LockedAccountException("用户名被锁定");
}
// 然后你需要从数据库中查询出来 用户名,密码用于realm 的验证
// 验证经过数据库查询出来的密码 和 token里面前端携带的用户密码之间是否相同
// 源码中 可能是将 info 和token 之间进行对比分析的, 即shiro 会完成密码的比对
Object principal = username; // 这个好像无所谓
Object credentials = "a94d5cd0079cfc8db030e1107de1addd1903a01b";
String realmName = getName(); // info 专门用来存储 经过查询数据库后的用户信息
// shiro 通过比较token,info 来进行数据的确定
AuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
return info;
} public static void main(String[] args){
String hashAlgorithmName = "SHA1";
Object credentials = "123456";
Object salt = null;
int hashIterations = 1024;
Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
System.out.println(result);
}
}

  

三、 使用shiro 实现认证登录

实现流程: 用户在登录页面点击登录, 访问登录对应的url, 将用户名和密码封装成 Token 对象 , 执行 Login 方法,然后

在authenticator 认证器下, 调用realm  的  doGetAuthenticationInfo方法,  将用户信息对象 token 传递给

realm,根据token对象中用户名信息查询用户在数据中的用户的密码信息, 并将密码信息封装成 AuthenticationInfo 对象进

行返回,在authenticator内部通过对Token 对象 以及  AuthenticationInfo 对象 进行对比, 来进行用户验证。

问题:查一个基本的用户登录为什么要这么的复杂, 直接用户输入的密码和用户的数据库中密码进行比对不就ok了, 感觉

    需要像上面这样复杂?

原因:第一: 一般在数据库中存储的密码不是明文,都经过加密操作,然后用户登录时候输入的密码, 你需要进行加密操作后, 再

进行对比,shiro 中就从表面上看较为简单的实现, 只需要在配置realm的文件中 配置 加密算法, 加密次数, shiro 内部就实现

了对你用户输入的密码进行加密操作

             <property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value = "1024"></property> 第二:如果在用户登录时候, 如何查看用用户的权限?shiro 提供了一个 authorizer 授权器,用于查询用户的权限信息,当用户
登录成功authorizer 会调用 realm的doGetAuthorizationInfo 方法,根据 PrincipalCollection 信息中的用户名信息,进行数据
库中查询用户的权限信息,并将权限信息封装成SimpleAuthorizationInfo对象返回
四、shiro jstl 标签的使用
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> // 引入shiro标签库
<html>
<head>
<title>Title</title>
</head>
<h1> List </h1>
<a href = "user.jsp"> user </a>
<br><br> <a href = "admin.jsp"> admin </a>
<br><br> <a href = "test"> test admin.jsp </a>
<br><br> <a href = "cache">test cache </a>
<br><br> <%--shiro jstl 标签能够根据用户的角色和权限, 显示不同的内容--%> <%--没有认证的显示的内容--%>
<shiro:guest>
everyBody can get
<br><br>
</shiro:guest> <%--只有角色admin,才显示--%>
<shiro:hasRole name="admin">
Only admin can get
<br><br>
</shiro:hasRole> <shiro:hasRole name = "user">
only user can get
<br><br>
</shiro:hasRole> <%--只有认证过的用户,才显示--%>
<shiro:authenticated>
only authenticated user can get
<br><br>
</shiro:authenticated> <a href="logout"> logout </a>
<%--如果没有登出, shiro的缓存里面存储着用户的登录信息, 然后用户登录都会成功--%>
</body>
</html>
 
五、 用户权限的注解开发

  使用@RequiresRoles(“xxx”)标注的方法, controller 只有 对应的 权限的用户才能够访问

    @RequiresRoles("admin")
@RequestMapping("/test")
public String test(HttpSession session){
session.setAttribute("key", "hello");
serviceTest.testSession(session);
return "redirect: admin.jsp";
}

  

六、 shiro 的 缓存使用

  因为在页面中使用 shiro 的 jstl 标签, 会去不断的去查询当前用户的权限信息, 所以这里进行优化的话

就是使用缓存, 可以使用ehcache , redis 等 缓存来实现




还是写的太垃圾了, 忘见谅

  

shiro 基础使用的更多相关文章

  1. Shiro基础

    Factory<T>接口(org.apache.shiro.util.Factory) 接口的getInstance()方法是泛型方法,可以用来创建SecurityManager接口对象 ...

  2. Shiro 基础教程

    原文地址:Shiro 基础教程 博客地址:http://www.extlight.com 一.前言 Apache Shiro 是 Java 的一个安全框架.功能强大,使用简单的Java安全框架,它为开 ...

  3. Apache Shiro:【1】Shiro基础及Web集成

    Apache Shiro:[1]Shiro基础及Web集成 Apache Shiro是什么 Apache Shiro是一个强大且易于使用的Java安全框架,提供了认证.授权.加密.会话管理,与spri ...

  4. Shiro框架 - 【shiro基础知识】

     转载:https://segmentfault.com/a/1190000013875092#articleHeader27  读完需要 63 分钟   前言 本文主要讲解的知识点有以下: 权限管理 ...

  5. Apache Shiro 快速入门教程,shiro 基础教程 (这篇文章非常好)

    第一部分 什么是Apache Shiro     1.什么是 apache shiro :   Apache Shiro是一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理 ...

  6. Apache Shiro 快速入门教程,shiro 基础教程

    第一部分 什么是Apache Shiro     1.什么是 apache shiro :   Apache Shiro是一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理 ...

  7. 【原】Spring整合Shiro基础搭建[3]

    1.前言 上个Shiro Demo基础搭建是基于官方的快速入门版本,没有集成其他框架,只是简单的通过Main方法来执行Shiro工作流程,并测试一下比较核心的函数:但在企业开发中一般都会集成Sprin ...

  8. Shiro基础知识08----拦截器介绍(转)

    1 拦截器介绍 Shiro使用了与Servlet一样的Filter接口进行扩展:所以如果对Filter不熟悉可以参考<Servlet3.1规范>http://www.iteye.com/b ...

  9. shiro基础学习(四)—shiro与项目整合

    一.认证 1.配置web.xml   2.配置applicationContext.xml      在applicationContext.xml中配置一个bean,ID和上面的过滤器的名称一致. ...

  10. shiro基础学习(三)—shiro授权

    一.入门程序 1.授权流程        2.授权的三种方式 (1)编程式: 通过写if/else 授权代码块完成. Subject subject = SecurityUtils.getSubjec ...

随机推荐

  1. 分布式大牛详解Zookeeper底层原理

    很多学员都在反馈,说zk很难学,学的不是很明白,在这里,我继续带着大家详解一遍Zookeeper 首先zk是什么呢首先肯定是一个个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用 ...

  2. oracle数据库创建实例

    数据库已经安装完成,可以正常登陆查看用户等操作 system用户只能用normal身份登陆em.除非你对它授予了sysdba的系统权限或者syspoer系统权限. sys用户具有“SYSDBA”或者“ ...

  3. DEVOPS技术实践_08:声明式管道语法

    简介 前面简单的做了管道的实验,看了一下的它的效果 声明式管道是Groovy语法中的一个更简单和结构化的语法.下面主要学习明式管道语法. 一 声明式管道的基本结构 以上节的代码为例 node { de ...

  4. vue-awesome-swiper手动滑动后不再自动轮播的问题

    <swiper :options="swiperOption" ref="mySwiper" > <!--轮播图内容--> </s ...

  5. 浅谈Java的默认和静态方法

    目录 浅谈Java的默认和静态方法 Java新增默认方法有啥用 Java新增的静态方法有啥用 浅谈Java的默认和静态方法 允许在接口中声明默认方法和静态方法,是JDK1.8新增的特性.存在即合理,两 ...

  6. Tomcat启动失败原因

    Tomcat启动失败原因 一.Tomcat启动时,要求被加载的项目必须拥有独立路径名称 发布的两个工程具有相同路径名称,这是不允许. 二.8080端口号已经被占用了 启动失败原因,就是8085端口上, ...

  7. 二、webdriver API

    目录 1. webdriver中常用属性 2. 浏览器页面操作 3. 鼠标操作 4. 键盘操作 5. 下拉框操作 1. webdriver中常用属性 import time from selenium ...

  8. docker-网络驱动

    网络驱动程序 Docker的网络子系统是可插拔的,使用驱动程序.默认情况下存在多个驱动程序,并提供核心网络功能: bridge:默认网络驱动程序.如果未指定驱动程序,则这是要创建的网络类型.当的应用程 ...

  9. OpenJ_Bailian 2815 城堡问题(DFS)

    题目传送门OpenJ_Bailian 2815 描述 1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---### ...

  10. es lucene搜索及聚合流程源码分析

    本文以TermQuery,GlobalOrdinalsStringTermsAggregator为例,通过代码,分析es,lucene搜索及聚合流程.1:协调节点收到请求后,将search任务发到相关 ...