Java岗大厂面试百日冲刺【Day43】—— Shrio1

转载自: Java岗大厂面试百日冲刺【Day43】—— Shrio1

本文已获得原作者 _陈哈哈 授权并经过重新整理规划后发布。

本栏目Java开发岗高频面试题主要出自以下各技术栈:Java基础知识、集合容器、并发编程、JVM、Spring全家桶、MyBatis等ORMapping框架、MySQL数据库、Redis缓存、RabbitMQ消息队列、Linux操作技巧等。

面试题1:你来简单介绍一下Shiro框架吧?

Apache Shiro是Java的一个安全框架。使用Shiro可以非常容易的开发出足够好的应用。其不仅可以用在JavaSE环境,也可以用在JavaEE环境。Shiro可以帮助我们完成功能:认证、授权、加密、会话管理、与Web集成、缓存等功能。

InterviewForJavaByThreeQuestionsADay43-01.webp

Shiro包括三个核心组件:Subject,SecurityManager和Realm。

  • Subject:即当前操作用户。Subject在shiro中是一个接口,定义了很多认证授权的方法,外部程序通过Subject进行认证授权,而Subject通过SecurityManager进行认证授权。其实SecurityManager才是实际的执行者。
  • SecurityManager:安全管理器,所有与安全有关的操作都会与SecurityManager交互,且管理着所有的Subject,是shiro的核心,负责与shiro其他组件进行交互,如通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。SecurityManager也是一个接口,继承了Authenticator,Authorizer,SessionManager三个接口
  • Realm:Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。Shiro从Realm获取安全数据(如用户,角色,权限);也就是说SecurityManager要验证用户身份或操作权限,需要从Realm获取相应数据来判断(用户是否能登录,是否拥有什么权限等)。

追问1:Shiro常见的权限控制方式有哪几种?

  • 方法注解权限控制
  • 页面标签权限控制
  • 代码级别权限控制
  • URL级别权限控制

1. 方法注解权限控制:

基于代理技术实现,首先要在spring配置文件中进行声明开启shiro注解,然后在代码方法上用注解声明调用该方法需要什么权限。

<!-- 开启shiro框架注解支持 -->
<bean id="defaultAdvisorAutoProxyCreator" 
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!-- 必须使用cglib方式为Action对象创建代理对象 -->
<property name="proxyTargetClass" value="true"/>
</bean>

<!-- 配置shiro框架提供的切面类,用于创建代理对象 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>

然后在方法上声明:

@RequiresPermissions("user-delete")
//执行这个方法,需要当前用户具有user-delete这个权限
public String deleteUser(){
	staffService.deleteUser(user_name);
	return LIST;
}

2. 页面标签权限控制:

首先要在jsp页面进入表签:

<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
然后包裹权限控制的内容
<shiro:hasPermission name="user-delete">
	<!— 有权限 —>  
	<button>删除用户</button>
</shiro:hasPermission>

3.代码级别权限控制:

public String deleteUser(Model model){

	Subject subject = SecurityUtils.getSubject();  
	if(subject..checkPermission("user-delete")) {  
		//有权限  
	} else {  
		//无权限  
	}
}

4. URL拦截权限控制:

基于filter过滤器实现,我们在spring配置文件中配置shiroFilter时配置

<!--指定URL级别拦截策略  -->
<property name="filterChainDefinitions"> 
	<value>
		/css/ = anon
		/js/ = anon
		/images/ = anon
		/validatecode.jsp = anon
		/login.jsp = anon
		/user/userlogin = anon
		/user/deleteUser = perms["user-delete"]
		/** = authc
	</value>
</property>
正常情况下,没有授权会跳转到为授权(登录)页面

anon:表示不拦截(匿名用户可访问)
user:使用rememberme的用户可访问
perms:对应权限可访问
role:对应的角色才能访问
authc:认证用户可访问

使用shiro进行权限控制时 这四种方法并不是进行单一的使用,是相互结合的使用从而完整的进行权限控制。

追问2:你还知道Shiro的其他组件么?简单说一下

InterviewForJavaByThreeQuestionsADay43-02.webp

  • Subject: 与应用交互的用户
  • SecurityManager: 相当于SpringMVC中的DispatcherServlet,所有具体的交互都由SecurityManager控制;它管理着所有的Subject,且负责进行认证,授权,会话和缓存的管理
  • Realm: 安全实体数据源,可以有1个或多个

除了以上三个核心组件外,还包括:

  • Authenticator: 认证器, 对用户身份进行验证;Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,也可以自定义
  • Authorizer: 授权器,决定用户是否有权限进行某种操作,控制着用户能访问应用中的哪些功能
  • SessionManager: 管理session的生命周期(可以实现单点登录)
  • CacheManager: 缓存管理器
  • Cryptography: 密码管理模块

面试题2:说一下Shiro认证和授权过程

认证流程

InterviewForJavaByThreeQuestionsADay43-03.webp

  • 首先调用 Subject.login(token)进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager()设置;
  • SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
  • Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
  • Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
  • Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。
shiro中有三种认证策略的具体实现:

AtleastOneSuccessfulStrategy: 只要有一个realm验证成功,则成功
FirstSuccessfulStrategy: 第一个realm验证成功,则成功,后续realm将被忽略
AllSuccessfulStrategy: 所有realm成功,验证才成功

授权流程

shiro判断用户是否有权限首先会从realm中获取用户所拥有的权限角色信息,然后再匹配当前的角色或权限是否包含,从而判定用户是否有权限。

InterviewForJavaByThreeQuestionsADay43-04.webp

  • 首先调用 Subject.isPermitted/hasRole接口,其会委托给 SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
  • Authorizer 是真正的授权者,如果我们调用如 isPermitted(“user:view”),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;
  • 在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;
  • Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个 Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted/hasRole 会返回 true,否则返回 false 表示授权失败。继承 AuthorizingRealm而不是实现 Realm 接口;

面试题3:Shiro中常见的异常有哪些?

异常 原因
UnknownAccountException 帐号不存在
IncorrectCredentialsException 密码错误
DisabledAccountException 帐号被禁用
LockedAccountException 帐号被锁定
ExcessiveAttemptsException 登录失败次数过多
ExpiredCredentialsException 凭证过期