关于java:权限认证Shiro安全框架

30次阅读

共计 16597 个字符,预计需要花费 42 分钟才能阅读完成。

Shiro 平安框架简介

  1. Shiro 概述

Shiro 是 apache 旗下一个开源平安框架(http://shiro.apache.org/),它将软件系统的平安认证相干的性能抽取进去,实现用户身份认证,权限受权、加密、会话治理等性能,组成了一个通用的平安认证框架。应用 shiro 就能够十分疾速的实现认证、受权等性能的开发,升高零碎老本。

用户在进行资源拜访时,要求零碎要对用户进行权限管制, 其具体流程如图 - 1 所示:

图 -1

  1. Shiro 概要架构

在概念层面,Shiro 架构蕴含三个次要的理念,如图 - 2 所示:

图 -2

其中:

  1. Subject : 主体对象,负责提交用户认证和受权信息。
  2. SecurityManager:平安管理器,负责认证,受权等业务实现。
  3. Realm:畛域对象,负责从数据层获取业务数据。
  4. Shiro 具体架构

Shiro 框架进行权限治理时, 要波及到的一些外围对象, 次要包含: 认证治理对象, 受权治理对象, 会话治理对象, 缓存治理对象, 加密治理对象以及 Realm 治理对象 (畛域对象: 负责解决认证和受权畛域的数据访问题) 等,其具体架构如图 - 3 所示:

图 -3

其中:

  1. Subject(主体): 与软件交互的一个特定的实体(用户、第三方服务等)。
  2. SecurityManager(平安管理器) :Shiro 的外围,用来协调治理组件工作。
  3. Authenticator(认证管理器): 负责执行认证操作。
  4. Authorizer(受权管理器): 负责受权检测。
  5. SessionManager(会话治理): 负责创立并治理用户 Session 生命周期,提供一个强有力的 Session 体验。
  6. SessionDAO: 代表 SessionManager 执行 Session 长久(CRUD)动作,它容许任何存储的数据挂接到 session 治理根底上。
  7. CacheManager(缓存管理器): 提供创立缓存实例和治理缓存生命周期的性能。
  8. Cryptography(加密管理器): 提供了加密形式的设计及治理。
  9. Realms(畛域对象): 是 shiro 和你的应用程序平安数据之间的桥梁。

Shiro 框架认证拦挡实现(filter)

  1. Shiro 根本环境配置

  2. 增加 shiro 依赖

实用 spring 整合 shiro 时,须要在 pom.xml 中增加如下依赖:

<dependency>

 <groupId>org.apache.shiro</groupId>

 <artifactId>shiro-spring</artifactId>

 <version>1.5.3</version>

</dependency>
  1. Shiro 外围对象配置

    基于 SpringBoot 实现的我的项目中,没有提供 shiro 的自动化配置,须要咱们本人配置。

第一步: 创立 SpringShiroConfig 类。要害代码如下:

package com.cy.pj.common.config;

/**@Configuration 注解形容的类为一个配置对象,

 * 此对象也会交给 spring 治理

 */

@Configuration

public class SpringShiroConfig {

}

第二步:在 Shiro 配置类中增加 SecurityManager 配置(这里肯定要应用 org.apache.shiro.mgt.SecurityManager 这个接口对象),要害代码如下:

@Bean

public SecurityManager securityManager() {

 DefaultWebSecurityManager sManager=

 new DefaultWebSecurityManager();

 return sManager;

}

第三步: 在 Shiro 配置类中增加 ShiroFilterFactoryBean 对象的配置。通过此对象设置资源匿名拜访、认证拜访。要害代码如下:

@Bean

public ShiroFilterFactoryBean shiroFilterFactory (SecurityManager securityManager) {

 ShiroFilterFactoryBean sfBean=

 new ShiroFilterFactoryBean();

 sfBean.setSecurityManager(securityManager);

 // 定义 map 指定申请过滤规定(哪些资源容许匿名拜访, 哪些必须认证拜访)

 LinkedHashMap<String,String> map= new LinkedHashMap<>();

 // 动态资源容许匿名拜访:"anon"

 map.put("/bower_components/**","anon");

 map.put("/build/**","anon");

 map.put("/dist/**","anon");

 map.put("/plugins/**","anon");

 // 除了匿名拜访的资源, 其它都要认证 ("authc") 后拜访

 map.put("/**","authc");

 sfBean.setFilterChainDefinitionMap(map);

 return sfBean;

 }

其配置过程中, 对象关系如下图 - 4 所示:


图 -4

  1. Shiro 登陆页面出现

  2. 服务端 Controller 实现

  • 业务形容及设计实现

当服务端拦挡到用户申请当前, 断定此申请是否曾经被认证, 如果没有认证应该先跳转到登录页面。

  • 要害代码剖析及实现.

第一步:在 PageController 中增加一个出现登录页面的办法, 要害代码如下:

@RequestMapping("doLoginUI")

public String doLoginUI(){return "login";}

第二步:批改 SpringShiroConfig 类中 shiroFilterFactorybean 的配置,增加登陆 url 的设置。要害代码见 sfBean.setLoginUrl(“/doLoginUI”)局部。

@Bean

public ShiroFilterFactoryBean shiroFilterFactory (SecurityManager securityManager) {

 ShiroFilterFactoryBean sfBean=

 new ShiroFilterFactoryBean();

 sfBean.setSecurityManager(securityManager);

 sfBean.setLoginUrl("/doLoginUI");

// 定义 map 指定申请过滤规定(哪些资源容许匿名拜访,

哪些必须认证拜访)

 LinkedHashMap<String,String> map=

 new LinkedHashMap<>();

 // 动态资源容许匿名拜访:"anon"

 map.put("/bower_components/**","anon");

 map.put("/modules/**","anon");

 map.put("/dist/**","anon");

 map.put("/plugins/**","anon");

 // 除了匿名拜访的资源, 其它都要认证 ("authc") 后拜访

 map.put("/**","authc");

 sfBean.setFilterChainDefinitionMap(map);

 return sfBean;

}
  1. 客户端页面实现

  • 业务形容及设计实现。

在 /templates/pages/ 增加一个 login.html 页面, 而后将我的项目部署到 web 服务器, 并启动测试运行.

  • 要害代码剖析及实现。

具体代码见我的项目中 login.html。

  1. Shiro 框架认证业务实现

  2. 认证流程剖析

身份认证即断定用户是否是零碎的非法用户,用户拜访系统资源时的认证(对用户身份信息的认证)流程图 - 5 所示:

图 -5

其中认证流程剖析如下:

  1. 零碎调用 subject 的 login 办法将用户信息提交给 SecurityManager
  2. SecurityManager 将认证操作委托给认证器对象 Authenticator
  3. Authenticator 将用户输出的身份信息传递给 Realm。
  4. Realm 拜访数据库获取用户信息而后对信息进行封装并返回。
  5. Authenticator 对 realm 返回的信息进行身份认证。

思考:不应用 shiro 框架如何实现认证操作?filter,intercetor。

  1. 认证服务端实现

  2. 外围业务剖析

认证业务 API 解决流程剖析,如图 - 6 所示:

图 -6

  1. DAO 接口定义

  • 业务形容及设计实现。

在用户数据层对象 SysUserDao 中,按特定条件查问用户信息,并对其进行封装。

  • 要害代码剖析及实现。

在 SysUserDao 接口中,增加依据用户名获取用户对象的办法,要害代码如下:

SysUser findUserByUserName(String username)。

  1. Mapper 元素定义

  • 业务形容及设计实现。

依据 SysUserDao 中定义的办法,在 SysUserMapper 文件中增加元素定义。

  • 要害代码剖析及实现。

基于用户名获取用户对象的办法,要害代码如下:

<select id="findUserByUserName"

 resultType="com.cy.pj.sys.entity.SysUser">

 select *

 from sys_users 

 where username=#{username}

 </select>
  1. Service 接口及实现

  • 业务形容及设计实现。

本模块的业务在 Realm 类型的对象中进行实现,咱们编写 realm 时,要继承

AuthorizingRealm 并重写相干办法,实现认证及受权业务数据的获取及封装。

  • 要害代码剖析及实现。

第一步:定义 ShiroUserRealm 类,要害代码如下:

package com.cy.pj.sys.service.realm;

@Service

public class ShiroUserRealm extends AuthorizingRealm {

 @Autowired

 private SysUserDao sysUserDao;

 /**

 * 设置凭证匹配器(与用户增加操作应用雷同的加密算法)

 */

 @Override

 public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {

 // 构建凭证匹配对象

 HashedCredentialsMatcher cMatcher=

 new HashedCredentialsMatcher();

 // 设置加密算法

 cMatcher.setHashAlgorithmName("MD5");

 // 设置加密次数

 cMatcher.setHashIterations(1);

 super.setCredentialsMatcher(cMatcher);

 }

 /**

 * 通过此办法实现认证数据的获取及封装, 零碎

 * 底层会将认证数据传递认证管理器,由认证

 * 管理器实现认证操作。*/

 @Override

 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)

 throws AuthenticationException {//1. 获取用户名(用户页面输出)

 UsernamePasswordToken upToken=

 (UsernamePasswordToken)token;

 String username=upToken.getUsername();

 //2. 基于用户名查问用户信息

 SysUser user=

 sysUserDao.findUserByUserName(username);

 //3. 断定用户是否存在

 if(user==null)

 throw new UnknownAccountException();

 //4. 断定用户是否已被禁用。if(user.getValid()==0)

 throw new LockedAccountException();

 //5. 封装用户信息

 ByteSource credentialsSalt=

 ByteSource.Util.bytes(user.getSalt());

 // 记住:构建什么对象要看办法的返回值

 SimpleAuthenticationInfo info=

 new SimpleAuthenticationInfo(user,//principal (身份)

 user.getPassword(),//hashedCredentials

 credentialsSalt, //credentialsSalt

 getName());//realName

 //6. 返回封装后果

 return info;// 返回值会传递给认证管理器(后续

 // 认证管理器会通过此信息实现认证操作)

 }

 ....

}

第二步:对此 realm,须要在 SpringShiroConfig 配置类中,注入给 SecurityManager 对象, 批改 securityManager 办法,见黄色背景局部,例如:

@Bean

public SecurityManager securityManager(Realm realm) {

 DefaultWebSecurityManager sManager=

 new DefaultWebSecurityManager();

 sManager.setRealm(realm);

 return sManager;

}
  1. Controller 类实现

  • 业务形容及设计实现。

在此对象中定义相干办法,解决客户端的登陆申请,例如获取用户名,明码等而后提交该 shiro 框架进行认证。

  • 要害代码剖析及实现。

第一步:在 SysUserController 中增加解决登陆的办法。要害代码如下:

 @RequestMapping("doLogin")

 public JsonResult doLogin(String username,String password){

 //1. 获取 Subject 对象

 Subject subject=SecurityUtils.getSubject();

 //2. 通过 Subject 提交用户信息, 交给 shiro 框架进行认证操作

 //2.1 对用户进行封装

 UsernamePasswordToken token=

 new UsernamePasswordToken(

 username,// 身份信息

 password);// 凭证信息

 //2.2 对用户信息进行身份认证

 subject.login(token);

 // 剖析:

 //1)token 会传给 shiro 的 SecurityManager

 //2)SecurityManager 将 token 传递给认证管理器

 //3)认证管理器会将 token 传递给 realm

 return new JsonResult("login ok");

 }

第二步:批改 shiroFilterFactory 的配置,对 /user/doLogin 这个门路进行匿名拜访的配置,查看如下黄色标记局部的代码:

@Bean

public ShiroFilterFactoryBean shiroFilterFactory (SecurityManager securityManager) {

 ShiroFilterFactoryBean sfBean=

 new ShiroFilterFactoryBean();

 sfBean.setSecurityManager(securityManager);

 // 如果没有认证申请先拜访此认证的 url

 sfBean.setLoginUrl("/doLoginUI");

 // 定义 map 指定申请过滤规定(哪些资源容许匿名拜访, 哪些必须认证拜访)

 LinkedHashMap<String,String> map=

 new LinkedHashMap<>();

 // 动态资源容许匿名拜访:"anon"

 map.put("/bower_components/**","anon");

 map.put("/build/**","anon");

 map.put("/dist/**","anon");

 map.put("/plugins/**","anon");

 map.put("/user/doLogin","anon"); //authc 示意,除了匿名拜访的资源, 其它都要认证 ("authc") 后能力拜访拜访

 map.put("/**","authc");

 sfBean.setFilterChainDefinitionMap(map);

 return sfBean;

 }

第三步:当咱们在执行登录操作时, 为了进步用户体验, 可对系统中的异样信息进行解决, 例如, 在对立异样解决类中增加如下办法:

@ExceptionHandler(ShiroException.class)

 @ResponseBody

 public JsonResult doHandleShiroException(ShiroException e) {JsonResult r=new JsonResult();

 r.setState(0);

 if(e instanceof UnknownAccountException) {r.setMessage("账户不存在");

 }else if(e instanceof LockedAccountException) {r.setMessage("账户已被禁用");

 }else if(e instanceof IncorrectCredentialsException) {r.setMessage("明码不正确");

 }else if(e instanceof AuthorizationException) {r.setMessage("没有此操作权限");

 }else {r.setMessage("系统维护中");

 }

 e.printStackTrace();

 return r;

 }
  1. 认证客户端实现

  2. 编写用户登陆页面

在 /templates/pages/ 目录下增加登陆页面(login.html)。

  1. 异步登陆操作实现

点击登录操作时, 将输出的用户名, 明码异步提交到服务端。

$(function () {$(".login-box-body").on("click",".btn",doLogin);

 });

 function doLogin(){

 var params={username:$("#usernameId").val(),

 password:$("#passwordId").val()}

 var url="user/doLogin";

 $.post(url,params,function(result){if(result.state==1){

 // 跳转到 indexUI 对应的页面

 location.href="doIndexUI?t="+Math.random();}else{$(".login-box-msg").html(result.message);

 }

 });

 }
  1. 退出操作配置实现

在 SpringShiroConfig 配置类中,批改过滤规定,增加黄色标记局部代码的配置, 请看如下代码:

@Bean

public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {

 ShiroFilterFactoryBean sfBean=

 new ShiroFilterFactoryBean();

 sfBean.setSecurityManager(securityManager);

 // 如果没有认证申请先拜访此认证的 url

 sfBean.setLoginUrl("/doLoginUI");

 // 定义 map 指定申请过滤规定(哪些资源容许匿名拜访, 哪些必须认证拜访)

 LinkedHashMap<String,String> map=new LinkedHashMap<>();

 // 动态资源容许匿名拜访:"anon"

 map.put("/bower_components/**","anon");

 map.put("/build/**","anon");

 map.put("/dist/**","anon");

 map.put("/plugins/**","anon");

 map.put("/user/doLogin","anon");

 map.put("/doLogout","logout"); 

 // 除了匿名拜访的资源, 其它都要认证 ("authc") 后拜访

 map.put("/**","authc");

 sfBean.setFilterChainDefinitionMap(map);

 return sfBean;

 }

Shiro 框架受权过程实现

受权流程剖析
受权即对用户资源拜访的受权(是否容许用户拜访此资源),用户拜访系统资源时的受权流程如图 - 7 所示:

图 -7
其中受权流程剖析如下:
零碎调用 subject 相干办法将用户信息 (例如 isPermitted) 递交给 SecurityManager。
SecurityManager 将权限检测操作委托给 Authorizer 对象。
Authorizer 将用户信息委托给 realm。
Realm 拜访数据库获取用户权限信息并封装。
Authorizer 对用户受权信息进行断定。

 思考:思考不应用 shiro 如何实现受权操作?intercetor,aop。

增加受权配置
在 SpringShiroConfig 配置类中,增加受权时的相干配置:
第一步: 配置 bean 对象的生命周期治理(SpringBoot 能够不配置)。

@Bean
public LifecycleBeanPostProcessor   lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();
}

第二步: 通过如下配置要为指标业务对象创立代理对象(SpringBoot 中可省略)。

@DependsOn("lifecycleBeanPostProcessor")
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {return new DefaultAdvisorAutoProxyCreator();
}
    

第三步: 配置 advisor 对象,shiro 框架底层会通过此对象的 matchs 办法返回值 (相似切入点) 决定是否创立代理对象, 进行权限管制。

@Bean
public AuthorizationAttributeSourceAdvisor 
authorizationAttributeSourceAdvisor (SecurityManager securityManager) {
                        AuthorizationAttributeSourceAdvisor advisor=
                                new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
        return advisor;
}

阐明: 应用框架最重要的尊重规定, 框架规定指定了什么形式就应用什么形式。

受权服务端实现
外围业务剖析
受权时,服务端外围业务以及 API 剖析,如图 - 8 所示:

图 -8
Dao 实现
业务形容及设计实现。
基于登陆用户 ID,认证信息获取登陆用户的权限信息,并进行封装。
要害代码剖析及实现。
第一步:在 SysUserRoleDao 中定义基于用户 id 查找角色 id 的办法(如果办法曾经存在则无需再写),要害代码如下:

 List<Integer> findRoleIdsByUserId(Integer id);

第二步:在 SysRoleMenuDao 中定义基于角色 id 查找菜单 id 的办法,要害代码如下:

List<Integer> findMenuIdsByRoleIds(@Param("roleIds")List<Integer> roleIds);

第三步:在 SysMenuDao 中基于菜单 id 查找权限标识的办法,要害代码如下:

List<String> findPermissions(@Param("menuIds")
                        List<Integer> menuIds);

Mapper 实现
业务形容及设计实现。
基于 Dao 中办法,定义映射元素。
要害代码剖析及实现。
第一步:在 SysUserRoleMapper 中定义 findRoleIdsByUserId 元素。要害代码如下:

<select id="findRoleIdsByUserId"
            resultType="int">
           select role_id
           from sys_user_roles
           where user_id=#{userId}        
</select>

第二步: 在 SysRoleMenuMapper 中定义 findMenuIdsByRoleIds 元素。要害代码如下:

<select id="findMenuIdsByRoleIds"
         resultType="int">
         select menu_id
         from sys_role_menus
         where role_id in 
         <foreach collection="roleIds"
                  open="("
                  close=")"
                  separator=","
                  item="item">
               #{item}
         </foreach>
</select>

第三步: 在 SysMenuMapper 中定义 findPermissions 元素,要害代码如下:

<select id="findPermissions"
           resultType="string">
       select permission <!-- sys:user:update -->
       from sys_menus
       where id in 
       <foreach collection="menuIds"
                open="("
                close=")"
                separator=","
                item="item">
            #{item}
       </foreach>
   </select>

Service 实现
业务形容及设计实现。
在 ShiroUserReam 类中,重写对象 realm 的 doGetAuthorizationInfo 办法,并实现用户权限信息的获取以及封装,最初将信息传递给受权管理器实现受权操作。
要害代码剖析及实现。
批改 ShiroUserRealm 类中的 doGetAuthorizationInfo 办法,要害代码如下:

@Service
public class ShiroUserRealm extends AuthorizingRealm {
        @Autowired
        private SysUserDao sysUserDao;
        @Autowired
        private SysUserRoleDao sysUserRoleDao;
        @Autowired
        private SysRoleMenuDao sysRoleMenuDao;
        @Autowired
        private SysMenuDao sysMenuDao;
        /** 通过此办法实现受权信息的获取及封装 */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
                //1. 获取登录用户信息,例如用户 id
                SysUser user=(SysUser)principals.getPrimaryPrincipal();
                Integer userId=user.getId();
                //2. 基于用户 id 获取用户领有的角色(sys_user_roles)
                List<Integer> roleIds=
                sysUserRoleDao.findRoleIdsByUserId(userId);
                if(roleIds==null||roleIds.size()==0)
                throw new AuthorizationException();
                //3. 基于角色 id 获取菜单 id(sys_role_menus)
                List<Integer> menuIds=
                sysRoleMenuDao.findMenuIdsByRoleIds(roleIds);
            if(menuIds==null||menuIds.size()==0)
            throw new AuthorizationException();
                //4. 基于菜单 id 获取权限标识(sys_menus)
            List<String> permissions=
            sysMenuDao.findPermissions(menuIds);
                //5. 对权限标识信息进行封装并返回
            Set<String> set=new HashSet<>();
            for(String per:permissions){if(!StringUtils.isEmpty(per)){set.add(per);
                    }
            }
            SimpleAuthorizationInfo info=
            new SimpleAuthorizationInfo();
            info.setStringPermissions(set);
                return info;// 返回给受权管理器
        }。。。。}

受权拜访实形容现
在须要进行受权拜访的业务层(Service)办法上,增加执行此办法须要的权限标识,参考代码 @RequiresPermissions(“sys:user:update”)
阐明:此要注解肯定要增加到业务层办法上。

Shiro 扩大性能利用

Shiro 缓存配置
当咱们进行受权操作时, 每次都会从数据库查问用户权限信息, 为了进步受权性能, 能够将用户权限信息查问进去当前进行缓存, 下次受权时从缓存取数据即可。
Shiro 中内置缓存利用实现, 其步骤如下:
第一步: 在 SpringShiroConfig 中配置缓存 Bean 对象(Shiro 框架提供)。

@Bean
public CacheManager shiroCacheManager(){return new MemoryConstrainedCacheManager();
}

阐明: 这个 CacheManager 对象的名字不能写 cacheManager, 因为 spring 容器中曾经存在一个名字为 cacheManager 的对象了.
第二步: 批改 securityManager 的配置,将缓存对象注入给 SecurityManager 对象。
@Bean
public SecurityManager securityManager(

                    Realm realm,
                    CacheManager cacheManager) {
             DefaultWebSecurityManager sManager=
             new DefaultWebSecurityManager();
             sManager.setRealm(realm);
             sManager.setCacheManager(cacheManager);
             return sManager;

}
阐明: 对于 shiro 框架而言, 还能够借助第三方的缓存产品 (例如 redis) 对用户的权限信息进行 cache 操作.
Shiro 记住我
记住我性能是要在用户登录胜利当前, 如果敞开浏览器, 下次再拜访系统资源 (例如首页 doIndexUI) 时, 无需再执行登录操作。
客户端业务实现
在页面上选中记住我, 而后执行提交操作, 将用户名, 明码, 记住我对应的值提交到管制层,如图 - 9 所示:

图 -9
其客户端 login.html 中要害 JS 实现:

 function doLogin(){
          var params={username:$("#usernameId").val(),
                 password:$("#passwordId").val(),
                 isRememberMe:$("#rememberId").prop("checked"),
          }
          var url="user/doLogin";
          console.log("params",params);
          $.post(url,params,function(result){if(result.state==1){
                        // 跳转到 indexUI 对应的页面
                        location.href="doIndexUI?t="+Math.random();}else{$(".login-box-msg").html(result.message); 
                  }
                  return false;// 避免刷新时反复提交
          });
  }
服务端业务实现
服务端业务实现的具体步骤如下:
第一步: 在 SysUserController 中的 doLogin 办法中基于是否选中记住我,设置 token 的 setRememberMe 办法。@RequestMapping("doLogin")
         @ResponseBody
         public JsonResult doLogin(
                         boolean isRememberMe,
                         String username,
                         String password) {
                 //1. 封装用户信息
                 UsernamePasswordToken token=
                 new UsernamePasswordToken(username, password);
                 if(isRememberMe) {token.setRememberMe(true); 
                 }
                 //2. 提交用户信息
                 Subject subject=SecurityUtils.getSubject();
                 subject.login(token);//token 会提交给 securityManager
                 return new JsonResult("login ok");
         }
第二步: 在 SpringShiroConfig 配置类中增加记住我配置,要害代码如下:@Bean
         public RememberMeManager rememberMeManager() {
                 CookieRememberMeManager cManager=
                 new CookieRememberMeManager();
  SimpleCookie cookie=new SimpleCookie("rememberMe");
                 cookie.setMaxAge(7*24*60*60);
                 cManager.setCookie(cookie);
                 return cManager;
         }
第三步: 在 SpringShiroConfig 中批改 securityManager 的配置,为
securityManager 注入 rememberManager 对象。参考黄色局部代码。@Bean
         public SecurityManager securityManager(
                        Realm realm,CacheManager cacheManager
RememberMeManager rememberManager) {
                 DefaultWebSecurityManager sManager=
                 new DefaultWebSecurityManager();
                 sManager.setRealm(realm);
                 sManager.setCacheManager(cacheManager);
                 sManager.setRememberMeManager(rememberManager);
                 return sManager;
         }

第四步: 批改 shiro 的过滤认证级别,将 /=author 批改为 /=user, 查看黄色背景局部。

@Bean
         public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
                 ShiroFilterFactoryBean sfBean=
                 new ShiroFilterFactoryBean();
                 sfBean.setSecurityManager(securityManager);
                 // 如果没有认证申请先拜访此认证的 url
                 sfBean.setLoginUrl("/doLoginUI");
                 // 定义 map 指定申请过滤规定(哪些资源容许匿名拜访, 哪些必须认证拜访)
                 LinkedHashMap<String,String> map=
                                 new LinkedHashMap<>();
                 // 动态资源容许匿名拜访:"anon"
                 map.put("/bower_components/**","anon");
                 map.put("/build/**","anon");
                 map.put("/dist/**","anon");
                 map.put("/plugins/**","anon");
                 map.put("/user/doLogin","anon");
                 map.put("/doLogout", "logout");// 主动查 LoginUrl
                 // 除了匿名拜访的资源, 其它都要认证 ("authc") 后拜访
                 map.put("/**","user");//authc
                 sfBean.setFilterChainDefinitionMap(map);
                 return sfBean;
         }

阐明: 查看浏览器 cookie 设置, 可在浏览器中输出如下语句。
chrome://settings/content/cookies
Shiro 会话时长配置
应用 shiro 框架实现认证操作, 用户登录胜利会将用户信息写入到会话对象中, 其默认时长为 30 分钟, 如果须要对此进行配置, 可参考如下配置:
第一步:在 SpringShiroConfig 类中,增加会话管理器配置。要害代码如下:

@Bean   
public SessionManager sessionManager() {
                 DefaultWebSessionManager sManager=
                                 new DefaultWebSessionManager();
                 sManager.setGlobalSessionTimeout(60*60*1000);
                 return sManager;
}

第二步:在 SpringShiroConfig 配置类中,对平安管理器 securityManager 减少 sessionManager 值的注入,要害代码如下:

@Bean
public SecurityManager securityManager(
                        Realm realm,CacheManager cacheManager,
RememberMeManager rememberManager,
SessionManager sessionManager) {
                 DefaultWebSecurityManager sManager=
                 new DefaultWebSecurityManager();
                 sManager.setRealm(realm);
                 sManager.setCacheManager(cacheManager);
                 sManager.setRememberMeManager(rememberMeManager);
                 sManager.setSessionManager(sessionManager);
                 return sManager;
}

课堂练习:
1. 获取用户登陆信息,并将登陆用户名出现在零碎主页(starter.html)上.
第一步:定义一个工具类(ShiroUtils),获取用户登陆信息.

package com.cy.pj.common.util;
import org.apache.shiro.SecurityUtils;
import com.cy.pj.sys.entity.SysUser;
public class ShiroUtils {public static String getUsername() {return getUser().getUsername();}
          public static SysUser getUser() {return  (SysUser)
           SecurityUtils.getSubject().getPrincipal();
          }
}
第二步:批改 PageController 中的 doIndexUI 办法,代码如下:@RequestMapping("doIndexUI")
        public String doIndexUI(Model model) {SysUser user=ShiroUtils.getUser();
                model.addAttribute("user",user);
                return "starter";
        }

第三步:借助 thymeleaf 中的表达式间接在页面上 (starter.html) 获取登陆用户信息

  <span class="hidden-xs" id="loginUserId">[[${user.username}]]</span>

2. 批改登陆用户的明码?(参考用户模块文档)

剖析:
1)确定都要批改谁?(明码,盐值,批改工夫)
2)服务端的设计实现?(dao,service,controller)
3)客户端的设计实现?(异步提交用户明码信息)

Shiro 总结

  1. 重点和难点剖析

  2. shiro 认证过程剖析及实现(断定用户身份的合法性)。
  3. Shiro 受权过程剖析及实现(对资源拜访进行权限检测和受权)。
  4. Shiro 缓存,会话时长,记住我等性能实现。
  5. Bug 剖析

  6. SecurityManager 包名谬误。
  7. MD5 加密算法设置谬误。
  8. Realm 对象没有交给 spring 治理
  9. 用户名和明码接管谬误
  10. CacheManager 名字与 Spring 中内置的 CacheManager 名字抵触。
  11. 过滤规定配置谬误?

正文完
 0