shiro中文api_Shiro

a476776c74207dd863396d5c53016d90.png

1 shiro

Apache shiro 是一个 Java 安全框架。

功能:认证、授权、加密和会话管理功能

应用环境:JavaEE、JavaSE

ed6b98a69b2b64dc2ef6b0b399fd0157.png

Subject 可看做成一个用户

SecurityManager 框架的核心API

Reaim 域对象,用于取数据库中的数据,进行权限比对。

04e7b8565d5bed5ac75c508055b8ee49.png

| 名词 | 名词中文解释 | | -------------- | ------------ | | Subject | 主体 | | Security | 安全 | | Realm | 领域、范围 | | Authenticator | 认证器 | | Authentication | 认证 | | Authorizer | 授权器 | | Authorization | 授权 | | Cryptography | 密码、凭证 | | Credential | 证书、凭证 | | Matcher | 匹配器 | | Principal | 身份 |

shiro 配置文件

shiro.ini 文件放在 claspath 中,shiro会自动查找。其中格式是key/value键值对配置。

Ini 配置文件一般适合与用户少且不需要在运行时动态创建的情景下使用。

ini 配置文件有四大类:main,users,roles,urls

[main]

main 主要配置shiro 的一些对象,例如:securityManager,Realm,authenticator,authcStrategy

[users]

作用:配置一组静态的用户

格式:key:value ,key表示密码的名字,value 表示密码的值

zeros=1233

[roles]

作用:将角色和权限关联操作

格式:资源:操作

role1= printer:create,printer:query

[urls]

作用:拦截对应的 URL 请求。

2 实现简单认证

认证:验证用户是否合法。

2.1 实现步骤

导入 jar 包

junit-4.9.jar log4j-1.2.17.jar shiro-all-1.3.2.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar

编写 shiro.ini 配置文件

[users]zeros=1233

测试

package com.szxy.shiro;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;public class SampleAuthentication {@Testpublic void sampleAuthentication(){//构建  SecurityManagerFactory 工厂IniSecurityManagerFactory factory = new IniSecurityManagerFactory();//利用 SecurityManagerFactory 实例化  SecurityManager 对象SecurityManager securityManager = factory.getInstance();// 将 SecurityManager 设置到运行环境中SecurityUtils.setSecurityManager(securityManager);//通过SecurityUtils, 创建主体 SubjectSubject subject = SecurityUtils.getSubject();//创建用户密码令牌认证UsernamePasswordToken token = new UsernamePasswordToken("admin1","passwd");//验证身份subject.login(token);//查看结果System.out.println(subject.isAuthenticated());}
}

3 Realm 域

shiro 默认使用 IniRealm 源,默认从 init 配置文件中读取用户信息。

3.1 实现步骤

建立 users 表

注意:表名必须是 users 。jdbcRealm 查找数据库中的表就是 users 表。

导入 jar 包

com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar commons-beanutils-1.9.2.jar commons-logging-1.1.1.jar junit-4.9.jar log4j-1.2.17.jar mysql-connector-java-5.1.30.jar shiro-all-1.3.2.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar

编写 shiro.ini 配置文件

[main]
#配置Realm
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
#配置数据源
dataSource = com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass = com.mysql.jdbc.Driver
dataSource.jdbcUrl = jdbc:mysql:///rbac
dataSource.user = root
dataSource.password = rootjdbcRealm.dataSource = $dataSource#将 Realm 注入给 SecurityManager
securityManager.realm = $jdbcRealm

测试

同简单认证的测试方法

4 自定义 Realm

好处:可以给 securityManager 更加灵活的安全数据源(eg。jdbcRealm 中表和字段都限定了)

方式:通过实现 Realm 接口,或根据需要继承他的响应子类即可。 AuthenticatingRealm

需求: 使用自定义 Realm ,从而实现认证。

实现步骤

导入 jar 包

com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar commons-beanutils-1.9.2.jar commons-logging-1.1.1.jar junit-4.9.jar log4j-1.2.17.jar mysql-connector-java-5.1.30.jar shiro-all-1.3.2.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar

编写自定义 Realm

package com.szxy.realm;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.subject.PrincipalCollection;import com.mysql.jdbc.Driver;public class CustRealm extends  AuthenticatingRealm {private String principals; //用户名private String credentials;    //密码private String driverName = "com.mysql.jdbc.Driver";private String url = "jdbc:mysql:///rbac";private String user = "root";private String password = "root";@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// 使用 jdbc 连接数据库Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动/*Driver driver = new Driver();DriverManager.registerDriver(driver);*/Class.forName(driverName);//获取数据库连接conn =  DriverManager.getConnection(url, user, password);//操作数据库对象stat = conn.createStatement();//定义 sql 语句String sql  = "select username,password from users";//执行 查询语句rs = stat.executeQuery(sql);//获取 结果集if(rs.next()){principals = rs.getString("username");credentials = rs.getString("password");}} catch (SQLException | ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if(rs!=null){try {rs.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(stat!=null){try {stat.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(conn !=null){try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}//创建 AuthenticationInfo 接口 实现类SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(principals, credentials,"custRealm");return info;}
}

编写 shiro.ini 配置文件

[main]
#配置Realm
custRealm = com.szxy.realm.CustRealm#将 Realm 注入给 SecurityManager
securityManager.realm = $custRealm

测试

同上测试

5 加密方式

对称加密算法

加密的密钥与解密的密钥相同

26e9fafd36ad148358915bcd655f0d08.png

非对称算法算法

加密的密钥与解密的密钥不相同

公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。

公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。

ce1b7732b7a9505f49a42846000dc8b4.png

对称与非对称算法

f6707c75eb39871be012226b817c9cf5.png

散列算法比较

MD5加密、加盐与迭代

加盐

原因:相同的 password 生产相同的 Hash 值是相同

原理:给原文加入随机数生成新的MD5

加盐 salt:指往原文加入的随机数

迭代

加密的次数

| Md5Hash的构造方法 | 参数名用法 | | ------------------------------------------------------------ | ----------------------- | | public Md5Hash(Object source) | source指加密的数据 | | public Md5Hash(Object source, Object salt) | salt 加盐 | | public Md5Hash(Object source, Object salt, int hashIterations) | hashIterations 迭代次数 | | public Md5Hash() | 无参构造器 |

代码示例

package com.szxy.md5;import org.apache.shiro.crypto.hash.Md5Hash;public class TestMd5 {public static void main(String[] args) {//直接加密  Md5Hash md5 = new Md5Hash("123");System.out.println(md5);//202cb962ac59075b964b07152d234b70//加盐 salt md5 = new Md5Hash("123", "zwz");System.out.println(md5); //3b52ecfc4719fcb6c863208063548792//迭代,即加密的次数md5 = new Md5Hash("123", "zwz", 2);System.out.println(md5); //de231265fe7ec45af1404ded2f365001 }
}

6 凭证匹配器 Authentication

AuthenticatingRealm

修改 realm

//ByteSource.Utilbytes(salt)
package com.szxy.realm;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;public class CustRealm extends  AuthenticatingRealm{private String principals; //用户名private String credentials;    //密码private String driverName = "com.mysql.jdbc.Driver";private String url = "jdbc:mysql:///shiro";private String user = "root";private String password = "root";private String salt = null;   //加盐的盐值@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// 使用 jdbc 连接数据库Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动/*Driver driver = new Driver();DriverManager.registerDriver(driver);*/Class.forName(driverName);//获取数据库连接conn =  DriverManager.getConnection(url, user, password);//操作数据库对象stat = conn.createStatement();//定义 sql 语句String sql  = "select username,password,salt from starUsers";//执行 查询语句rs = stat.executeQuery(sql);//获取 结果集if(rs.next()){principals = rs.getString("username");credentials = rs.getString("password");salt  = rs.getString("salt");}} catch (SQLException | ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if(rs!=null){try {rs.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(stat!=null){try {stat.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(conn !=null){try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}ByteSource byteSource = ByteSource.Util.bytes(salt); //加盐//创建 AuthenticationInfo 接口 实现类SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(principals, credentials,byteSource,"customRealm");return info;}
}

配置 shiro 配置文件

[main]#配置凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher#设置凭证匹配器的相关属性
credentialsMatcher.hashAlgorithmName=MD5
credentialsMatcher.hashIterations=2#配置Realm
customRealm=com.szxy.realm.CustRealm#配置Realm的凭证匹配器属性
customRealm.credentialsMatcher=$credentialsMatcher#将Realm注入给SecurityManager
securityManager.realm=$customRealm

7 授权 Authorization

授权,又称访问控制,是对资源访问管理的过程。
即对于认证通过的用户,授予他可以访问某些资源的权限

授权方式

代码触发、注解触发、标签触发

授权流程图

fa566eee44afb59382e77beba059ecf4.png

配置文件

[main]#配置凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher#设置凭证匹配器的相关属性
credentialsMatcher.hashAlgorithmName=MD5
credentialsMatcher.hashIterations=2#配置Realm
customRealm=com.szxy.realm.CustRealm#配置Realm的凭证匹配器属性
customRealm.credentialsMatcher=$credentialsMatcher#将Realm注入给SecurityManager
securityManager.realm=$customRealm

代码示例

package com.szxy.realm;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;public class CustRealm extends  AuthorizingRealm{private String principals; //用户名private String credentials;    //密码private String driverName = "com.mysql.jdbc.Driver";private String url = "jdbc:mysql:///shiro";private String user = "root";private String password = "root";private String salt = null;   //加盐的盐值private String roleName;  //角色名称private String remark;// 验证的方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// 使用 jdbc 连接数据库Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动/*Driver driver = new Driver();DriverManager.registerDriver(driver);*/Class.forName(driverName);//获取数据库连接conn =  DriverManager.getConnection(url, user, password);//操作数据库对象stat = conn.createStatement();//定义 sql 语句String sql  = "select username,password,salt from starUsers";//执行 查询语句rs = stat.executeQuery(sql);//获取 结果集if(rs.next()){principals = rs.getString("username");credentials = rs.getString("password");salt  = rs.getString("salt");}} catch (SQLException | ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if(rs!=null){try {rs.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(stat!=null){try {stat.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(conn !=null){try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}ByteSource byteSource = ByteSource.Util.bytes(salt); //加盐//创建 AuthenticationInfo 接口 实现类SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(principals, credentials,byteSource,"customRealm");return info;}// 授权的方法@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {// 使用 jdbc 连接数据库Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动/*Driver driver = new Driver();DriverManager.registerDriver(driver);*/Class.forName(driverName);//获取数据库连接conn =  DriverManager.getConnection(url, user, password);//操作数据库对象stat = conn.createStatement();//定义 sql 语句//String sql  = "select rolename from roles";String  sql = "select * from permission"; //执行 查询语句rs = stat.executeQuery(sql);//获取 结果集if(rs.next()){//roleName = rs.getString("rolename");remark = rs.getString("remark");}} catch (SQLException | ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if(rs!=null){try {rs.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(stat!=null){try {stat.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(conn !=null){try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();   //info.addRole(roleName);         //添加角色信息info.addStringPermission(remark); //添加权限信息return info;}
}

测试

package com.szxy.shiro;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;public class TestShiro {@Testpublic void TestAuthorization(){//构建  SecurityManagerFactory 工厂IniSecurityManagerFactory factory = new IniSecurityManagerFactory();//利用 SecurityManagerFactory 实例化  SecurityManager 对象SecurityManager securityManager = factory.getInstance();// 将 SecurityManager 设置到运行环境中SecurityUtils.setSecurityManager(securityManager);//通过SecurityUtils, 创建主体 SubjectSubject subject = SecurityUtils.getSubject();//创建用户密码令牌认证UsernamePasswordToken token = new UsernamePasswordToken("admin","123");//验证身份subject.login(token);//查看结果System.out.println(subject.isAuthenticated());//验证权限//基于角色授权boolean flag = subject.hasRole("管理员1");System.out.println(flag);//权限授权boolean flag2 = subject.isPermitted("一级菜单,基本设置操作权限");System.out.println(flag2);}}

8 spring 整合Shiro

新建项目,导入 jar 包

编写配置文件

编写 web.xml

DelegatingFilterProxy

通过代理模式将 servlet 容器中 filter 同 spring 容器的 bean 关联起来

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><display-name>RBACDemo</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><!-- 监听 ServletContext ,注册  Spring 容器 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 指定 spring 配置文件的名称及位置 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-*.xml</param-value></context-param><!-- 注册 SpringMVC 容器 --><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定 SpringMVC 配置文件的位置 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:SpringMVC.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 开启编码过滤器 --><filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 注册 DelegatingFilterProxy 通过代理模式将 servlet 容器中 filter 同 spring 容器的 bean 关联起来--><filter><filter-name>delegatingFilterProxy</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><!--该属性为 true 表名启用引用 filter 的init() 和 destroy() --><init-param><param-name>targetFilterLifecycle</param-name><param-value>true</param-value></init-param><!--该属性设置 spring 容器中 filter 的bean的 id--><init-param><param-name>targetBeanName</param-name><param-value>shiroFilter</param-value></init-param>   </filter><filter-mapping><filter-name>delegatingFilterProxy</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

spring-shiro.xml

<!-- 注册凭证匹配器,并为其注入属性值-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><!-- 加密方式 --><property name="hashAlgorithmName" value="md5"></property><!-- 迭代次数 --><property name="hashIterations" value="2" ></property>
</bean><!-- 注册自定义 realm  -->
<bean id="customRealm" class="com.szxy.realm.CustomRealm"><property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean><!-- 注册 SecurityManager  -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="customRealm"></property>
</bean><!--注册 shiroFilterFactoryBean 注意:bean 的id 名称必须与过滤器中的名称一致-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"></property><property name="loginUrl" value="/login.do"></property><property name="successUrl" value="/jsp/users.jsp"></property><property name="unauthorizedUrl" value="/jsp/refuse.jsp"></property><!-- 设置过滤器链属性 --><property name="filterChainDefinitions"><value>/login.do=authc/**=anon</value></property>
</bean>

代码示例

9 DelegatingFilterProxy

DelegatingFilterProxy 源码分析

void initFilterBean() 初始化过滤器 bean 对象,并调用 Filter initDelegate(WebApplicationContext wac) 方法,

从 spring 容器取出 目标 target 的bean 对象,并对其他进行初始化操作。

@Override
protected void initFilterBean() throws ServletException {synchronized (this.delegateMonitor) {if (this.delegate == null) {// If no target bean name specified, use filter name.if (this.targetBeanName == null) {this.targetBeanName = getFilterName();}// Fetch Spring root application context and initialize the delegate early,// if possible. If the root application context will be started after this// filter proxy, we'll have to resort to lazy initialization.WebApplicationContext wac = findWebApplicationContext();if (wac != null) {this.delegate = initDelegate(wac); }}}//Initialize the Filter delegate, defined as bean the given Spring
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);if (isTargetFilterLifecycle()) {//该属性为 true 表名启用引用 filter 的init() 和 destroy() 交给 spring 容器管理 delegate.init(getFilterConfig());}return delegate;
}

10 spring 整合 Shiro 之注册

密码使用 md5 方式加密

表单序列化

使用该操作,可以直接获取表单数据,简化操作。

<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script><script type="text/javascript" >$(function(){$("#btn").click(function(){$.ajax({url:"/user/register",type:"POST",data:$("#myForm").serialize(),//表单序列化,传递表单数据success:function(data){alert(data);}});});});
</script>

md5加密

@Override
public int userRegister(User user) {//使用 md5 加密用户的密码,并使用用户名作为 salt 值Md5Hash newPassword = new Md5Hash(user.getPassword(),user.getUsername(), 2);user.setPassword(newPassword.toString());user.setSalt(user.getUsername());return userMapper.insertUser(user);
}

9 实现菜单授权

11 SessionMapper 的使用

sessionMamanager 会话管理器管理着应用中所有的 Subject 的会话的创建、维护、删除、失效、验证等工作。

Shiro 提供了三个默认实现类:

| 类名 | 功能 | | ------------------------------ | ------------------------------------------------------------ | | DefaultSessionManager | 用于 JavaSE 环境 | | ServletContainerSessionManager | 用于 Web 环境,直接使用 tomcat 容器管理对象 | | DefaultWebSessionManager | 用于Web 环境,替代 类名功能DefaultSessionManager用于 JavaSE 环境ServletContainerSessionManager,自己维护会话。 |

<!-- 注册 sessionManager  -->
<bean id="sessionManager" class="org.apache.shiro.session.mgt.DefaultSessionManager"><!-- 设置 session 超时时间  ,以毫秒为单位 ms   1s 等于 1000ms --><property name="globalSessionTimeout" value="500000"></property><property name="deleteInvalidSessions" value="true"></property>
</bean>

12 remeber me 功能实现

即登录成功后,下次免登录

实现步骤

用户类即及其引用类的都需要序列化

修改页面 index .jsp

修改 Spring-shiro.xml

13 Shiro 内置过滤器

1 认证过滤器

anon authcBasic auchc user

2 授权过滤器

perms roles ssl rest port

49fcfa7e4ca70b328c38af18db0e7c51.png

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"></property><property name="loginUrl" value="/user/login.do"></property><property name="successUrl" value="/user/loginSuccess.do"></property><property name="unauthorizedUrl" value="/jsp/refuse.jsp"></property><!-- 设置过滤器链属性 authc 认证过滤器,表示表单认证anon  放行,可以匿名访问,不需要认证user  用户过滤器,用于识别当前用户是否登录并保存密码  RememberMe--><property name="filterChainDefinitions"><value>/user/login.do=authc /user/loginSuccess.do=user/menu/showMenu.do=user/**=anon</value></property>
</bean>

注意

使用 Shiro 框架做用户登录的时候,若登录成功后,在使用浏览器回来之前的登录界面,这时就登录不上了,不仅是使用之前登录的账号,还是其他账号。

推测:可能是同一 浏览器登录后存在 cookie ,影响用户的二次登录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/557385.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM 学习二:类加载器子系统

1 类加载器子系统的作用 类加载器子系统负责从文件系统或者网络中加载 Class 文件&#xff0c;Class 文件在文件开关有特定的文件标识ClassLoader 只负责 Class 文件的加载&#xff0c;至于它是否可以运行&#xff0c;则由 Execution Engine&#xff08;执行引擎&#xff09;决…

JVM 学习三:类加载器

类加载器 1 类加载器的分类 JVM 支持两种类型的类加载器&#xff1a;引导类加载器&#xff08;Bootstrap ClassLoader&#xff09;和自定义类加载器&#xff08;User-Defined ClassLoader&#xff09; 从概念上来讲&#xff0c;自定义类加载器一般指的是程序中由开发人员自定…

JVM 学习四:类加载之双亲委派机制与沙箱安全机制

1 双亲委派机制 Java 虚拟机对 Class 文件的加载采用的是按需加载的方式&#xff0c;也就是说&#xff1a;当需要使用该类时才会将它的 Class 文件加载到内存生成 Class 对象&#xff0c;而且加载某个类的 Class 文件时&#xff0c;Java 虚拟机采用的是双亲委派模式&#xff0c…

Java8新特性:Stream介绍和总结

Java8新特性&#xff1a;Stream介绍和总结 什么是Stream 流&#xff08;Stream&#xff09;是数据渠道&#xff0c;用于操作数据源&#xff08;集合、数组等&#xff09;所生成的元素序列。 集合讲的是数据&#xff0c;流讲的是计算 注意&#xff1a; Stream自己不会存储元素…

URL传Base64 造成报错 Illegal base64 character 20

报错如下&#xff1a; errorInternal Server Error, messageIllegal base64 character 20, tracejava.lang.IllegalArgumentException: Illegal base64 character 20 at java.util.Base64Decoder.decode0(Base64.java:714)atjava.util.Base64Decoder.decode0(Base64.java:714) …

Linux 中使用 sort 指令分组排序详解

Linux 中使用 sort 指令分组排序详解 sort 中进行分组排序主要用到的选项为 -k&#xff0c;此文&#xff0c;我们着重于该选项的使用方式&#xff0c;用到的其它选项不做解释&#xff0c;有兴趣的同学可以查看帮助文档 1. 数据准备 现有数据如下&#xff0c;文件名 sort_so…

Shiro-单点登录原理

单点登录原理 一、单系统登录机制 1、http无状态协议 web应用采用browser/server架构&#xff0c;http作为通信协议。http是无状态协议&#xff0c;浏览器的每一次请求&#xff0c;服务器会独立处理&#xff0c;不与之前或之后的请求产生关联&#xff0c;这个过程用下图说明…

@Autowired作用在普通方法上

Autowired作用在普通方法上 Autowired作用在普通方法上&#xff0c;会在注入的时候调用一次该方法&#xff0c;如果方法中有实体参数&#xff0c;会对方法里面的参数进行装配&#xff0c;并调用一次该方法。这个可以用来在自动注入的时候做一些初始化操作。

@Autowired注解作用在方法上

Autowired注解作用在方法上 Autowired注解作用在方法上 &#xff08;1&#xff09;该方法如果有参数&#xff0c;会使用autowired的方式在容器中查找是否有该参数 &#xff08;2&#xff09;会执行该方法

Spring定时任务

Spring定时任务(一)&#xff1a;SpringTask使用 背景&#xff1a;在日常开发中&#xff0c;经常会用到任务调度这类程序。实现方法常用的有&#xff1a;A. 通过java.util.Timer、TimerTask实现。 B.通过Spring自带的SpringTask。 C. 通过Spring结合Quartz实现。本文我们将讲述…

Spring的@Scheduled注解实现定时任务

Spring的Scheduled注解实现定时任务 【简介篇】 项目经常会用到定时任务&#xff0c;实现定时任务的方式有很多种。在Spring框架中&#xff0c;实现定时任务很简单&#xff0c;常用的实现方式是使用注解Scheduled。 Scheduled 常用来实现简单的定时任务。例如凌晨1点跑批&am…

深入学习二叉树(一) 二叉树基础

深入学习二叉树(一) 二叉树基础 前言 树是数据结构中的重中之重&#xff0c;尤其以各类二叉树为学习的难点。一直以来&#xff0c;对于树的掌握都是模棱两可的状态&#xff0c;现在希望通过写一个关于二叉树的专题系列。在学习与总结的同时更加深入的了解掌握二叉树。本系列文…

深入学习二叉树(二) 线索二叉树

深入学习二叉树(二) 线索二叉树 1 前言 在上一篇简单二叉树的学习中&#xff0c;初步介绍了二叉树的一些基础知识&#xff0c;本篇文章将重点介绍二叉树的一种变形——线索二叉树。 2 线索二叉树 2.1 产生背景 现有一棵结点数目为n的二叉树&#xff0c;采用二叉链表的形式…

深入学习二叉树(三) 霍夫曼树

深入学习二叉树(三) 霍夫曼树 1 前言 霍夫曼树是二叉树的一种特殊形式&#xff0c;又称为最优二叉树&#xff0c;其主要作用在于数据压缩和编码长度的优化。 2 重要概念 2.1 路径和路径长度 在一棵树中&#xff0c;从一个结点往下可以达到的孩子或孙子结点之间的通路&…

深入学习二叉树(四) 二叉排序树

深入学习二叉树(四) 二叉排序树 1 前言 数据结构中&#xff0c;线性表分为无序线性表和有序线性表。 无序线性表的数据是杂乱无序的&#xff0c;所以在插入和删除时&#xff0c;没有什么必须遵守的规则&#xff0c;可以插入在数据尾部或者删除在数据尾部。但是在查找的时候&a…

红黑树 —— 原理和算法详细介绍

红黑树 —— 原理和算法详细介绍 R-B Tree简介 R-B Tree&#xff0c;全称是Red-Black Tree&#xff0c;又称为“红黑树”&#xff0c;它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色&#xff0c;可以是红(Red)或黑(Black)。 红黑树的特性: 每个节点或…

微服务雪崩效应与 Hystrix

文章目录微服务雪崩效应微服务中常见的容错方案常见的服务容错思路Hystrix 简介微服务雪崩效应 微服务系统中, 每一个服务专心于自己的业务逻辑, 并对外提供相应的接口, 看上去似乎耦合度比较低, 但经常会遇见这样一种场景: 可以看到, 当 C 服务挂掉时, B 服务还在不断地调用…

时间复杂度到底怎么算

时间复杂度到底怎么算 算法&#xff08;Algorithm&#xff09;是指用来操作数据、解决程序问题的一组方法。对于同一个问题&#xff0c;使用不同的算法&#xff0c;也许最终得到的结果是一样的&#xff0c;但在过程中消耗的资源和时间却会有很大的区别。 那么我们应该如何去衡…

十分钟搞定时间复杂度(算法的时间复杂度)

十分钟搞定时间复杂度&#xff08;算法的时间复杂度&#xff09; 我们假设计算机运行一行基础代码需要执行一次运算。 int aFunc(void) {printf("Hello, World!\n"); // 需要执行 1 次return 0; // 需要执行 1 次 }那么上面这个方法需要执行 2 次运算 …

java实现简单二叉树

二叉树基本知识&#xff1a; 一、树的定义 树是一种数据结构&#xff0c;它是由n&#xff08;n>1&#xff09;个有限结点组成一个具有层次关系的集合。 树具有的特点有&#xff1a; &#xff08;1&#xff09;每个结点有零个或多个子结点 &#xff08;2&#xff09;没有…