首页 / 时尚 / 珠宝 / 正文

shiro(Shiro登录验证与鉴权核心流程详解)

放大字体  缩小字体 来源:手机贴膜价格 2026-04-17 17:04  浏览次数:8

在Web项目的安全架构中,登录验证与权限控制是保障系统安全的核心环节。Shiro作为一款轻量级的安全框架,通过过滤器(Filter)与拦截器(Interceptor)的协同工作,提供了完整且灵活的登录验证与鉴权解决方案。本文将从核心概述、核心组件、登录验证流程、权限鉴权流程、过滤器、拦截器及实践建议七个维度,系统拆解其实现逻辑与应用细节,助力开发者深入理解并灵活运用Shiro构建安全防护体系。

一、核心概述:双层安全防护体系

Shiro登录验证与鉴权的核心设计思想,是构建“过滤器链前置拦截+拦截器方法级增强”的双层管控模式。过滤器负责URL级别的粗粒度安全校验(如是否登录、URL是否允许匿名访问),确保非法请求在进入业务层前被阻断;拦截器基于AOP思想实现方法级别的细粒度权限控制(如方法所需的具体角色、权限),精准管控业务逻辑的访问权限。两者协同配合,形成从请求入口到业务执行的全链路安全校验闭环。

核心流程总览:用户发起请求后,先经过Web容器过滤器链,再进入Shiro核心过滤器链完成基础校验;校验通过后,经自定义或框架拦截器完成方法级权限校验,最终到达Controller层处理业务逻辑。任意一层校验失败,均直接拦截请求并返回对应结果,有效减少无效业务处理开销。

Shiro登录验证与鉴权核心流程详解nerror="javascript:errorimg.call(this);">

二、核心组件:安全机制的基石

Shiro的安全校验机制依赖一系列核心组件的协同工作,各组件分工明确,共同完成身份验证、权限控制、会话管理等核心功能。

1. 核心组件及功能

组件

功能

Shiro Filter

各种验证流程的入口,实现URL级别的粗粒度校验

Subject

代表登录人,记录session、凭证等信息,定义验证所需基本方法,每次请求创建新实例

SecurityManager

核心管理器,负责管理Subject、session等信息,辅助Subject实现各项功能

Session

类似Servlet Session,每个登录用户对应唯一Session

Realm

需开发者实现,用于获取用户权限、角色、身份等核心信息

AuthenticationInfo

通过Realm获取,用于身份验证的核心信息载体

AuthorizationInfo

通过Realm获取,用于权限验证的核心信息载体

AuthenticationToken

封装请求中的凭证信息(如用户名、密码)

CredentialsMatcher

核心用于密码验证,对比请求凭证与系统存储凭证的一致性

PasswordService

用于密码生成,辅助CredentialsMatcher完成密码验证

AuthenticationStrategy

多Realm场景下的身份验证策略,类似投票机制决定验证是否通过

Authenticator

负责执行身份验证的核心逻辑

2. 组件间核心关系

Shiro登录验证与鉴权核心流程详解nerror="javascript:errorimg.call(this);">

组件协同逻辑:用户请求触发Subject创建,Subject通过SecurityManager调用Authenticator完成身份验证;Authenticator依托AuthenticationStrategy,从Realm获取AuthenticationInfo并通过CredentialsMatcher校验凭证;权限验证时,SecurityManager调用Authorizer,从Realm获取AuthorizationInfo完成权限匹配;过滤器与拦截器作为入口,串联各组件形成完整校验链路。

三、登录验证流程:身份合法性校验全链路

登录验证流程的核心目标是校验用户身份合法性,核心链路为“请求拦截→凭证获取→凭证校验→会话创建”,具体实现依赖Filter与核心组件的协同工作。

1. 登录验证流程总览

Shiro登录验证与鉴权核心流程详解nerror="javascript:errorimg.call(this);">

2. 核心方法调用链路

Shiro登录验证与鉴权核心流程详解nerror="javascript:errorimg.call(this);">

3. 关键方法解析

AbstractShiroFilter.doFilterInternal:请求拦截入口

protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)        throws ServletException, IOException {    Throwable t = null;    try {        final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);        final ServletResponse response = prepareServletResponse(request, servletResponse, chain);        // 每次请求创建新的Subject        final Subject subject = createSubject(request, response);        // 将Subject绑定到当前线程,调用FormAuthenticationFilter处理        subject.execute(new Callable() {            public Object call() throws Exception {                updateSessionLastAccessTime(request, response);                executeChain(request, response, chain);                returnnull;            }        });    } catch (ExecutionException ex) {        t = ex.getCause();    } catch (Throwable throwable) {        t = throwable;    }}    

核心作用:预处理请求/响应对象,创建Subject并绑定到当前线程,触发后续登录验证逻辑。

FormAuthenticationFilter.onAccessDenied:登录请求判断

protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {    // 判断是否为登录请求    if (isLoginRequest(request, response)) {        if (isLoginSubmission(request, response)) {            if (log.isTraceEnabled()) {                log.trace("Login submission detected.  Attempting to execute login.");            }            // 触发登录验证            return executeLogin(request, response);        } else {            if (log.isTraceEnabled()) {                log.trace("Login page view.");            }            returntrue;        }    } else {        if (log.isTraceEnabled()) {            log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +                    "Authentication url [" + getLoginUrl() + "]");        }        // 非登录请求跳转至登录页        saveRequestAndRedirectToLogin(request, response);        returnfalse;    }}    

核心作用:区分登录请求与普通请求,仅对登录提交请求触发验证流程,非登录请求引导至登录页。

ModularRealmAuthenticator.authenticate:验证逻辑分发

// 验证策略选择protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {    assertRealmsConfigured();    Collection<Realm> realms = getRealms();    if (realms.size() == 1) {        // 单Realm场景:直接执行普通用户名密码验证        return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);    } else {        // 多Realm场景:按策略执行验证(全成功/至少一个成功/首个成功)        return doMultiRealmAuthentication(realms, authenticationToken);    }}// 单Realm用户名密码验证protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {    if (!realm.supports(token)) {        String msg = "Realm [" + realm + "] does not support authentication token [" +                token + "].  Please ensure that the appropriate Realm implementation is " +                "configured correctly or that the realm accepts AuthenticationTokens of this type.";        thrownew UnsupportedTokenException(msg);    }    // 调用Realm获取用户信息并验证    AuthenticationInfo info = realm.getAuthenticationInfo(token);    if (info == null) {        String msg = "Realm [" + realm + "] was unable to find account data for the " +                "submitted AuthenticationToken [" + token + "].";        thrownew UnknownAccountException(msg);    }    return info;}    

核心作用:根据Realm数量分发验证逻辑,支持单Realm普通验证与多Realm策略化验证,适配不同系统架构。

四、权限鉴权流程:已登录用户的权限校验

权限鉴权流程基于身份验证通过的前提,核心目标是校验已登录用户是否具备访问目标资源的权限,分为URL级(过滤器实现)和方法级(拦截器实现)两类,此处先阐述通用鉴权链路,方法级细节后续展开。

1. 权限鉴权流程总览

Shiro登录验证与鉴权核心流程详解nerror="javascript:errorimg.call(this);">

2. 核心方法调用链路

Shiro登录验证与鉴权核心流程详解nerror="javascript:errorimg.call(this);">

3. 关键方法解析

UserFilter.isAccessAllowed:用户有效性前置校验

publicclass UserFilter extends AccessControlFilter {    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {        // 不拦截登录流程        if (isLoginRequest(request, response)) {            returntrue;        } else {            // 校验用户是否已登录(含记住我状态)            Subject subject = getSubject(request, response);            return subject.getPrincipal() != null;        }    }    }    

核心作用:快速筛选无效用户,避免无效的后续权限校验,仅允许已登录(含记住我)用户进入权限校验环节。

PermissionsAuthorizationFilter.isAccessAllowed:权限精准校验

public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {    Subject subject = getSubject(request, response);    // 获取配置的目标资源所需权限    String[] perms = (String[]) mappedValue;    boolean isPermitted = true;    if (perms != null && perms.length > 0) {        // 单权限/多权限校验(默认“且”关系)        if (perms.length == 1) {            if (!subject.isPermitted(perms[0])) {                isPermitted = false;            }        } else {            if (!subject.isPermittedAll(perms)) {                isPermitted = false;            }        }    }    return isPermitted;}    

核心作用:校验用户是否具备访问当前URL所需的全部(或指定)权限,实现URL级的权限精准管控。

AuthorizingRealm.isPermitted:权限匹配核心逻辑

protected boolean isPermitted(Permission permission, AuthorizationInfo info) {    Collection<Permission> perms = getPermissions(info);    if (perms != null && !perms.isEmpty()) {        for (Permission perm : perms) {            // 对比用户拥有的权限与目标资源所需权限            if (perm.implies(permission)) {                returntrue;            }        }    }    returnfalse;}    

核心作用:通过权限匹配算法,判断用户已拥有的权限是否覆盖目标资源所需权限,是权限校验的核心逻辑实现。

五、过滤器:URL级粗粒度安全管控核心

Shiro过滤器基于Web容器Filter接口扩展,是URL级安全管控的核心组件,通过拦截请求URL,完成登录验证、权限校验、匿名访问控制等功能。其核心优势在于配置灵活,无需修改业务代码即可实现安全管控,覆盖大部分常规安全场景。

1. 过滤器层级结构

Shiro过滤器采用“抽象基类+具体实现”的层级设计,基础类提供通用能力,实现类聚焦业务校验,结构清晰且扩展性强:

  • 基础过滤器:定义核心骨架,提供通用功能。如PathMatchingFilter负责URL模式匹配(支持?、*、**通配符),是所有URL相关过滤器的父类;AdviceFilter提供请求前后增强点,支持日志记录、资源清理等扩展操作。
  • 验证过滤器:基于基础类扩展,实现具体校验逻辑。分为登录状态验证(如FormAuthenticationFilter、UserFilter)和权限验证(如PermissionsAuthorizationFilter、RolesAuthorizationFilter)两类。

2. 内置默认过滤器枚举

Shiro通过DefaultFilter枚举定义常用内置过滤器,可直接通过枚举名称在配置文件中引用,简化配置流程:

public enum DefaultFilter {    // 匿名访问过滤器:无需登录即可访问(登录页、公开接口等)    anon(AnonymousFilter.class),    // 表单登录过滤器:处理表单登录请求,校验用户名密码    authc(FormAuthenticationFilter.class),    // HTTP基本认证过滤器:基于HTTPBasic协议验证(适用于API)    authcBasic(BasicHttpAuthenticationFilter.class),    // 登出过滤器:清除会话信息,销毁登录状态    logout(LogoutFilter.class),    // 禁止会话创建过滤器:适用于无状态接口    noSessionCreation(NoSessionCreationFilter.class),    // 权限校验过滤器:验证用户是否具备指定权限    perms(PermissionsAuthorizationFilter.class),    // 端口校验过滤器:验证请求端口是否符合配置    port(PortFilter.class),    // REST风格权限过滤器:基于HTTP方法匹配权限(适用于RESTful接口)    rest(HttpMethodPermissionFilter.class),    // 角色校验过滤器:验证用户是否具备指定角色    roles(RolesAuthorizationFilter.class),    // SSL过滤器:强制HTTPS访问    ssl(SslFilter.class),    // 用户状态过滤器:验证用户是否为有效用户(登录/记住我)    user(UserFilter.class);}    

3. 常见配置示例与规则

(1)YML配置示例

shiro:filter-chain-definitions:    # 公开接口:允许匿名访问    -/api/public    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {        // 核心逻辑:允许访问则放行,否则执行拒绝处理        return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);    }        protected abstract boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;        protected abstract boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception;}    

核心逻辑总结:采用“短路逻辑”,先通过isAccessAllowed判断是否允许访问,通过则直接放行;未通过则执行onAccessDenied处理(如跳转登录页、返回403),确保校验流程统一且高效。

六、拦截器:方法级细粒度权限控制

Shiro拦截器基于AOP思想,实现方法级别的细粒度权限控制,弥补了过滤器URL级控制的局限性。其不仅适用于Web环境,也可用于普通Java应用,适用性更广,尤其适合同一URL对应不同方法需不同权限、方法内部权限校验等复杂场景。

1. 实现原理

Shiro拦截器通过动态代理机制实现权限校验,核心流程如下:

  1. 通过注解(如@RequiresRoles、@RequiresPermissions)标记需要权限校验的方法;
  2. 项目启动时,Shiro扫描带有注解的方法,为其创建动态代理对象;
  3. 调用目标方法时,先执行代理对象中的拦截器逻辑,完成权限校验;
  4. 校验通过则执行目标方法,失败则抛出异常并中断执行。

2. 核心注解与使用示例

Shiro提供一系列注解标记方法权限需求,可作用于方法或类(类级注解对所有方法生效):

注解名称

核心作用

使用示例

@RequiresAuthentication

要求用户主动登录(排除记住我状态)

@RequiresAuthentication




@RequiresGuest

要求用户为访客(未登录且非记住我)

@RequiresGuest




@RequiresPermissions

要求具备指定权限(支持多权限与通配符)

// 需同时具备order:add和order:edit
@RequiresPermissions({"order:add", "order:edit"})
// 具备其一即可
@RequiresPermissions(value = {"order:delete", "order:query"}, logical = Logical.OR)

@RequiresRoles

要求具备指定角色(支持多角色)

// 需同时具备admin和manager
@RequiresRoles({"admin", "manager"})
// 具备其一即可
@RequiresRoles(value = {"user", "guest"}, logical = Logical.OR)

@RequiresUser

要求为有效用户(登录/记住我)

@RequiresUser public ListgetUserOrders() { ... }

3. 使用注意事项

  • 注解生效条件:集成Spring时需确保Shiro AOP自动代理开启(默认开启),否则注解无法被扫描;
  • 异常处理:校验失败会抛出UnauthorizedException(无权限)、UnauthenticatedException(未登录)等,需通过全局异常处理器捕获并返回友好响应;
  • 优先级:过滤器校验优先于拦截器,过滤器校验失败时,不会执行到拦截器逻辑;
  • 非Web适用:不依赖Web容器,可在普通Java应用中手动创建代理对象使用。

七、总结与实践建议

Shiro登录验证与鉴权的核心价值,在于通过“过滤器+拦截器”的双层架构,实现了“URL级粗粒度控制+方法级细粒度控制”的全链路安全防护。过滤器负责前置拦截,快速阻断非法请求;拦截器负责后置精准管控,适配复杂业务权限需求,两者协同构建了灵活、高效的安全体系。

实践应用建议:

通过合理运用Shiro的核心组件与流程,可快速构建稳固的系统安全架构,兼顾开发效率与安全可靠性。

打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心