【SSH框架/国际物流商综平台】-04 Shiro安全框架( 认证、授权)hibernate关联关系 (一对多、多对一,多对多) casecade/inverse Hibernate.cfg.xml

1.知识回顾

1)搞清hibernate配置对象的关系

绝招:拿范例来背,权限架构,部门+用户+用户扩展信息+角色+模块

2)部门的自关联

public class Dept implements Serializable {
	private String id;
	private Set<User> users  = new HashSet<User>(0);//部门与用户    一对多
	
	private String deptName;//部门名称
	private Dept parent; //父部门  自关联  子部门与父部门     多对一
	private Integer state;//状态    1代表启用    0代表停用
 <!-- 自关联  子部门与父部门     多对一 -->
      <many-to-one name="parent" class="Dept" column="PARENT_ID"></many-to-one>

name实体中的配置的对象属性
class对应实体对象,写全路径cn.itcast.jk.domain.Dept有时简写Dept,必须配置package
column对于数据库表中的外键

3)部门和用户,一对多

 <!-- private Set<User> users  = new HashSet<User>(0);//部门与用户    一对多 -->
      <set name="users">
         <key column="DEPT_ID"></key>
         <one-to-many class="User"/>
      </set>

Set标签,它是个集合,在实体对象中配置Set users
name属性在实体中配置的集合的名称
casecade 级联,级联保存,删除(save-update,delete,delete-orphan,all,all- delete-orphan)
inverse交给另外一方来维护
key外键
one-to-many.class —对多具体调用的实体
面试:cascade 与 inverse 区别?
Cascade主要用于级联操作(如:级联添加,删除)
Inverse主要用于控制权是否要反转,一般将控制权放在多方
True代表控制权要反转,就交给多方维护,效率会提高
当删除部门时,级联删除部门下的所有用户。
lnverse="false”它是默认值可以不配
Update user set deptld=null where deptld=l;〃解决父子关系 Delete from user where deptld is null;〃先干掉孩子
Delete from dept where id=l;〃自杀
如果inverse="true”代表多方维护关系
Delete from user where deptld=l;〃 自杀
Delete from dept where id=l;〃自杀
False代表一方维护,它是默认值

4) 用户和部门,多对一,双向关联

public class User extends BaseEntity{
	private String id;
	private Dept dept;//用户与部门   多对一
	private Userinfo userinfo ;  //用户与用户扩展信息    一对一
	private Set<Role> roles = new HashSet<Role>(0);//用户与角色   多对多
	private String userName;//用户名
	private String password;//密码  要加密
	private Integer state;//状态
<!-- private Dept dept;//用户与部门   多对一 -->
      <many-to-one name="dept" class="Dept" column="DEPT_ID"></many-to-one>

Name配置关联的对象
Class调用的实体对象
Column夕卜键
用户和用户扩展信息,一对一,单向关联

<!-- 	private Userinfo userinfo ;  //用户与用户扩展信息    一对一 -->
      <one-to-one name="userinfo" class="Userinfo" cascade="all"></one-to-one>

Name配置实体中声明的对象
Class调用的实体对象
Cascade 级联
将用户,用户扩展信息表中的主键生成策略:assigned
在程序代码中,将用户,用户扩展信息的id设置为同一个取值。

5) 用户和角色,多对多

<!-- private Set<Role> roles = new HashSet<Role>(0);//用户与角色   多对多 -->
      <set name="roles" table="ROLE_USER_P">
         <key column="USER_ID"></key>
         <many-to-many class="Role" column="ROLE_ID"></many-to-many>
      </set>

Name在实体配置关联对象
Table多对多,配置中间表
Key外键
Many-to-many多对多,class配置关联对象,column外键,order-by排序,表中有这个排序
java学院宋江
字段
没有配置级联,没有配置inverse;(双向关联,例如:删除角色和不影响用户)
修改了用户的映射文件:

6)角色和用户,多对多

  <!-- private Set<User> users = new HashSet<User>(0);//角色与用户    多对多 -->
	  <set name="users" table="ROLE_USER_P">
	     <key column="ROLE_ID"></key>
	     <many-to-many class="User" column="USER_ID"></many-to-many>
	  </set>

7)角色和模块,多对多,双向关联,同上

[面试:byte/short/int/char/varchar 执行效率]
Byte>short>lnt>cha r>varchar
为什么你的id还使用varchar呢?(你想分布式)
Mysql数据库设计表的主键时,直接使用int并带上mysql数据库自增(autojncrement)
面试:请说出char与varchar的区别?
Char长度固定,执行效率更高,可能造成空间浪费
Varchar长度不固定剩余的空间会进行回收,运行效率低
补充角色模块:

public class Role extends BaseEntity{
	private String id;
	private Set<User> users = new HashSet<User>(0);//角色与用户    多对多
	private Set<Module> modules = new HashSet<Module>(0);//角色与模块    多对多
	private String name;//角色名
	private String remark;//备注
	private String orderNo;//排序号
  <!-- private Set<Module> modules = new HashSet<Module>(0);//角色与模块    多对多 -->
	  <set name="modules" table="ROLE_MODULE_P">
	     <key column="ROLE_ID"></key>
	     <many-to-many class="Module" column="MODULE_ID" order-by="ORDER_NO"></many-to-many>
	  </set>

8)模块和角色,多对多,双向关联,同上.

<!-- private Set<Role> roles = new HashSet<Role>(0);//模块与角色   多对多 -->
	    <set name="roles" table="ROLE_MODULE_P">
	        <key column="MODULE_ID"></key>
	        <many-to-many class="Role" column="ROLE_ID" order-by="ORDER_NO"></many-to-many>
	    </set>
public class Module extends BaseEntity {
	private String id;
	
	private Set<Role> roles = new HashSet<Role>(0);//模块与角色   多对多
	private String parentId;  //父模块的编号
	private String parentName;//父模块的名称  冗余  用空间换时间
	private String name;  //模块名
	private Integer layerNum;//层数   
	private Integer isLeaf;//叶子
	private String ico;  //图片
	private String cpermission;//权限
	private String curl;//路径
	private Integer ctype;//菜单的类型:主菜单,左侧菜单   ,按钮
	private Integer state;//状态
	private String belong;//从属于
	private String cwhich;//
	private Integer quoteNum;//引用次数
	private String remark;//备注
	private Integer orderNo;//排序号

9)Hibernate.cfg.xml

<!--  加载映射文件-->
		<mapping resource="cn/itcast/jk/domain/Dept.hbm.xml"></mapping>
		<mapping resource="cn/itcast/jk/domain/User.hbm.xml"></mapping>
		<mapping resource="cn/itcast/jk/domain/Userinfo.hbm.xml"></mapping>
		<mapping resource="cn/itcast/jk/domain/Role.hbm.xml"></mapping>
		<mapping resource="cn/itcast/jk/domain/Module.hbm.xml"></mapping>

Shiro安全框架( 认证、授权)

2.传统登录方式

在这里插入图片描述

3. Shiro安全框架实现登录

在这里插入图片描述

4.什么是Shiro ?

它是一个安全框架,用于解决系统的认证和授权问题,同时提供了会话管理,数据加密 机制。

5.Shiro的内部组织结构?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

加密

加密分类:
(1)、对称加密
双方使用的同一个密匙,既可以加密又可以解密,这种加密方法称为对称加密,也称单密匙加密。
(2)、非对称加密
一对密匙由公钥和私钥组成(可以使用很多对密匙)。私钥解密公钥加密数据,公钥解密私钥加密数据(私钥公钥可以互相加密解密)。

加密算法分类
(1)、单项加密
单项加密是不可逆的,也就是只能加密,不能解密。通常用来传输类型用户名和密码,直接将加密后的数据提交到后台,因为后台不需要知道用户名和密码,可以直接将接收到的加密后的数据存储到数据库
(2)、双向加密
通常分为对称性加密算法和非对称性加密算法,对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行 加解密了。非对称算法与之不同,发送双方A,B事先均生成一堆密匙,然后A将自己的公有密匙发送给B,B将自己的公有密匙发送给A,如果A要给B发送消 息,则先需要用B的公有密匙进行消息加密,然后发送给B端,此时B端再用自己的私有密匙进行消息解密,B向A发送消息时为同样的道理。

常见的算法
在这里插入图片描述

6.应用程序如何使用Shiro框架?

在这里插入图片描述
在这里插入图片描述

Realm:域,Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息。从这个意义上讲,Realm 实质上是一个安全相关的 DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro 。当配置 Shiro时,你必须至少指定一个 Realm ,用于认证和(或)授权。配置多个 Realm 是可以的,但是至少需要一个。
Shiro 内置了可以连接大量安全数据源(又名目录)的 Realm,如 LDAP、关系数据库(JDBC)、类似 INI 的文本配置资源以及属性文件等。如果缺省的 Realm 不能满足需求,你还可以插入代表自定义数据源的自己的 Realm 实现。功能
Realm能做的工作主要有以下几个方面:
身份验证(getAuthenticationInfo 方法)验证账户和密码,并返回相关信息
权限获取(getAuthorizationInfo 方法) 获取指定身份的权限,并返回相关信息
令牌支持(supports方法)判断该令牌(Token)是否被支持
令牌有很多种类型,例如:HostAuthenticationToken(主机验证令牌),UsernamePasswordToken(账户密码验证令牌)
这里主来说明一下关于前两点验证方面的逻辑,因为令牌一般用的都是 UsernamePasswordToken,哪怕用 HostAuthenticationToken,也没必要细讲,这个函数很少用到。

7.Shiro使用时要配置相关过滤器

在这里插入图片描述
在这里插入图片描述

 <!-- Shiro Security filter  filter-name这个名字的值将来还会在spring中用到  -->
   <!-- 注意:shiro的filter必须在struts2的filter之前,否则action无法创建 -->

    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

8.菜单的管理如何实现?

在这里插入图片描述

/WEB-INF/pages/home/title.jsp
<div id="menuContent">
	<!--  <span id="topmenu" onclick="toModule('home');">系统首页</span><span id="tm_separator"></span>
	<span id="topmenu" onclick="toModule('cargo');">货运管理</span><span id="tm_separator"></span>
	<span id="topmenu" onclick="toModule('stat');">统计分析</span><span id="tm_separator"></span>
	<span id="topmenu" onclick="toModule('baseinfo');">基础信息</span><span id="tm_separator"></span>
	<span id="topmenu" onclick="toModule('sysadmin');">系统管理</span> 
	<span id="topmenu" onclick="toModule('sysadmin');">班级管理</span>  -->
	 
	 
	 <!-- 当jsp页面碰到shiro标签时就执行AuthRealm中授权方法 -->
	 <shiro:hasPermission name="系统首页">
	<span id="topmenu" onclick="toModule('home');">系统首页</span><span id="tm_separator"></span>
	</shiro:hasPermission>
	<shiro:hasPermission name="货运管理">
		<span id="topmenu" onclick="toModule('cargo');">货运管理</span><span id="tm_separator"></span>
	</shiro:hasPermission>
	<shiro:hasPermission name="统计分析">
	<span id="topmenu" onclick="toModule('stat');">统计分析</span><span id="tm_separator"></span>
	</shiro:hasPermission>
	<shiro:hasPermission name="基础信息">
	<span id="topmenu" onclick="toModule('baseinfo');">基础信息</span><span id="tm_separator"></span>
	</shiro:hasPermission>
	<shiro:hasPermission name="系统管理">
	<span id="topmenu" onclick="toModule('sysadmin');">系统管理</span>
	</shiro:hasPermission>
	<shiro:hasPermission name="流程管理">
	<span id="topmenu" onclick="toModule('activiti');">流程管理</span>
	</shiro:hasPermission> 

</div>
/WEB-INF/pages/leftmenu.jsp
<ul>
            <c:set var="aaa" value=""/>
            <!-- 遍历当前登录用户的角色列表 -->
			<c:forEach items="${_CURRENT_USER.roles }" var="role">
			       <!-- 遍历每个角色下的模块 -->
			       <c:forEach items="${role.modules }" var="module">
			            <!-- 如果该模块没有输出过,则要进行输出,否则这个模块就不输出 -->
			            <c:if test="${(moduleName eq module.remark) and module.ctype==1  }">
				               <c:if test="${fn:contains(aaa,module.cpermission) eq false }">
				                  <c:set var="aaa" value="${aaa},${module.cpermission }"/>
			                      <li><a href="${ctx}/${module.curl}" onclick="linkHighlighted(this)" target="main" id="aa_1">${module.cpermission }</a></li>
			                 </c:if>  
			            </c:if>
			            
			       </c:forEach>
			</c:forEach>
</ul>

9. Shiro具体使用步骤

1)导入jar包

在这里插入图片描述

2)过滤器的配置
web.xml shiroFilter
   <!-- Shiro Security filter  filter-name这个名字的值将来还会在spring中用到  -->
   <!-- 注意:shiro的filter必须在struts2的filter之前,否则action无法创建 -->

    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
3)产生代理类的方式
applicationContext.xml
<!--Shiro安全框架产生代理子类的方式: 使用cglib方式-->
	<aop:aspectj-autoproxy proxy-target-class="true" />
applicationContext-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       
	xmlns:p="http://www.springframework.org/schema/p"  
	xmlns:context="http://www.springframework.org/schema/context"   
	xmlns:tx="http://www.springframework.org/schema/tx"  
	xmlns:aop="http://www.springframework.org/schema/aop"  
	xsi:schemaLocation="http://www.springframework.org/schema/beans    
	http://www.springframework.org/schema/beans/spring-beans.xsd    
	http://www.springframework.org/schema/aop    
	http://www.springframework.org/schema/aop/spring-aop.xsd    
	http://www.springframework.org/schema/tx    
	http://www.springframework.org/schema/tx/spring-tx.xsd    
	http://www.springframework.org/schema/context    
	http://www.springframework.org/schema/context/spring-context.xsd">
	
	<description>Shiro的配置</description>
	
	<!-- SecurityManager配置 -->
	<!-- 配置Realm-->
	<!-- 密码比较器 -->
	<!-- 代理如何生成? 用工厂来生成Shiro的相关过滤器-->
	<!-- 配置缓存:ehcache缓存 -->
	<!-- 安全管理 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- Single realm app.  If you have multiple realms, use the 'realms' property instead. -->
        <property name="realm" ref="authRealm"/><!-- 引用自定义的realm -->
        <!-- 缓存 -->
        <property name="cacheManager" ref="shiroEhcacheManager"/>
    </bean>

    <!-- 自定义权限认证 -->
    <bean id="authRealm" class="cn.itcast.jk.shiro.AuthRealm">
		<property name="userService" ref="userService"/>
		<!-- 自定义密码加密算法  -->
		<property name="credentialsMatcher" ref="passwordMatcher"/>
	</bean>
	
	<!-- 设置密码加密策略 md5hash -->
	<bean id="passwordMatcher" class="cn.itcast.jk.shiro.CustomCredentialsMatcher"/>

    <!-- filter-name这个名字的值来自于web.xml中filter的名字 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!--登录页面  -->
        <property name="loginUrl" value="/index.jsp"></property>
        <!-- 登录成功后 -->      
       <!--  <property name="successUrl" value="/home.action"></property> -->
        <property name="filterChainDefinitions">
            <!-- /**代表下面的多级目录也过滤 -->
            <value>
				/index.jsp* = anon
				/home* = anon
				/sysadmin/login/login.jsp* = anon
				/sysadmin/login/logout.jsp* = anon
				/login* = anon
				/logout* = anon
				/components/** = anon
				/css/** = anon
				/images/** = anon
				/js/** = anon
				/make/** = anon
				/skin/** = anon
				/stat/** = anon
				/ufiles/** = anon
				/validator/** = anon
				/resource/** = anon
				/** = authc
				/*.* = authc
            </value>
        </property>
    </bean>

    <!-- 用户授权/认证信息Cache, 采用EhCache  缓存 -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
    </bean>

    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 生成代理,通过代理进行控制 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>
    
    <!-- 安全管理器 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
	
</beans>
ehcache-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />
</ehcache>
4)在applicationContext.xml文件中加载shiro配置文件
<import resource="classpath:spring/applicationContext-shiro.xml"></import>
5)编写密码比较器 CustomCredentialsMatcher.java

<-(UsernamePasswordToken)AuthenticationToken
<-AuthenticationInfo

public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {

	//密码比较的方法   token代表用户在界面输入的用户名和密码     info代表从数据库中得到加密数据
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		//1.向下转型 
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		
		//2.将用户在界面输入的原始密码加密
		Object pwd = Encrypt.md5(new String(upToken.getPassword()), upToken.getUsername());
		
		//3.取出数据库中加密的密码
		Object dbPwd = info.getCredentials();
		
		return this.equals(pwd, dbPwd);
	}

	
}

在这里插入图片描述

Encrypt.java String md5(String password, String salt)
public class Encrypt {
	/*
	 * 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,
	 * 常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,
	 * 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,
	 * 可以到一些md5解密网站很容易的通过散列值得到密码“admin”,
	 * 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,
	 * 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。
	 */
	
	//高强度加密算法,不可逆
	public static String md5(String password, String salt){
		return new Md5Hash(password,salt,2).toString();
	}
	
	public static void main(String[] args) {
		System.out.println(new Md5Hash("123456","zhangsan"+"cgx",5).toString());
	}
	
	
}
6)编写自定义Realm域 AuthRealm.java

->AuthorizationInfo
->AuthenticationInfo(SimpleAuthenticationInfo)(用户界面输入的用户名,密码)
在这里插入图片描述
在这里插入图片描述

public class AuthRealm extends AuthorizingRealm {

	private UserService userService;
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	//授权   当jsp页面出现Shiro标签时,就会执行授权方法
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
		System.out.println("授权");
		User user = (User) pc.fromRealm(this.getName()).iterator().next();//根据realm的名字去找对应的realm
		
		Set<Role > roles = user.getRoles();//对象导航
		List<String> permissions = new ArrayList<String>();
		for(Role role :roles){
			//遍历每个角色 
			Set<Module> modules = role.getModules();//得到每个角色下的模块列表
			for(Module m :modules){
				permissions.add(m.getName());
			}
		}
		
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addStringPermissions(permissions);//添加用户的模块(权限)
		return info;
	}
	//认证   token 代表用户在界面输入的用户名和密码
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("认证");
		
		//1.向下转型
		UsernamePasswordToken upToken  = (UsernamePasswordToken) token;
		
		//2.调用业务方法,实现根据用户名查询
		String hql = "from User where userName=?";
		List<User> list = userService.find(hql, User.class, new String[]{upToken.getUsername()});
		if(list!=null && list.size()>0){
			User user = list.get(0);
			AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
			return info;   //此处如果返回,就会立即进入到密码比较器
		}
		
		return null;//就会出现异常
	}
	
}
7)将编写的AuthRealm域配置好

在这里插入图片描述

8)登录操作

LoginAction ->login()

private String username;
private String password;

public String login() throws Exception {
		
//		if(true){
//			String msg = "登录错误,请重新填写用户名密码!";
//			this.addActionError(msg);
//			throw new Exception(msg);
//		}
//		User user = new User(username, password);
//		User login = userService.login(user);
//		if (login != null) {
//			ActionContext.getContext().getValueStack().push(user);
//			session.put(SysConstant.CURRENT_USER_INFO, login);	//记录session
//			return SUCCESS;
//		}
//		return "login";

		
		if(UtilFuns.isEmpty(username)){
			return "login";
		}
		
		try {
			//1.得到Subject
			Subject subject = SecurityUtils.getSubject();
			//2.调用登录方法
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);
			subject.login(token);//当这一代码执行时,就会自动跳入到AuthRealm中认证方法
			
			//3.登录成功时,就从Shiro中取出用户的登录信息
			User user = (User) subject.getPrincipal();
			
			//4.将用户放入session域中
			session.put(SysConstant.CURRENT_USER_INFO, user);
			
		} catch (Exception e) {
			e.printStackTrace();
			request.put("errorInfo", "对不起,用户名或密码错误!");
			return "login";
		}
		return SUCCESS;
	}
	
9)实现测试,发现存在一个bug

在这里插入图片描述

10)测试认证过程成功,进入后台操作主页面。

在这里插入图片描述

11)测试授权过程
 <!-- 当jsp页面碰到shiro标签时就执行AuthRealm中授权方法 -->
	 <shiro:hasPermission name="系统首页">
	<span id="topmenu" onclick="toModule('home');">系统首页</span><span id="tm_separator"></span>
	</shiro:hasPermission>
12)添加用户时的bug修正

早期实现添加用户时,没有给密码,所以要补充,这样才可以使用添加的新用户实现登录操
作。

//新增
			String id = UUID.randomUUID().toString();
			entity.setId(id);
			entity.getUserinfo().setId(id);
			
			//补充Shiro添加后的bug
			entity.setPassword(Encrypt.md5(SysConstant.DEFAULT_PASS, entity.getUserName()));
			
			baseDao.saveOrUpdate(entity);//记录保存

10. Shiro运行流程分析

使用Shiro实现用户登录的过程

在这里插入图片描述

授权的过程

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值