shiro-登录验证

shiro实现登录验证,可以用它自身的方法来实现,也可以自定义方法来实现登录验证,了解了shiro的登录逻辑,实现自定义的验证逻辑就很简单
1、用shiro方法实现
shiro配置:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value = "/login" />
        <property name="successUrl" value = "/"  />
        <property name="unauthorizedUrl" value = "/unauthorize"/>
<property name="filterChainDefinitions">
            <value>
                /static/**=anon
                /login=authc
                /logout=logout
                /unauthorize=authc
                /**=user,perms
            </value>
        </property>
</bean>

由于shiro默认注册了FormAuthenticationFilter,所以配置中可以不需要为此方法定义bean,但有个前提,登录页面中的登录账号和密码,记住我的name必须和FormAuthenticationFilter默认的名称一致,如下图

如果登录页面的name和FormAuthenticationFilter不一致,则需要自己为FormAuthenticationFilter进行配置
<bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
        <property name="usernameParam" value="name"/>
        <property name="passwordParam" value="password1"/>
        <property name="rememberMeParam" value="rememberMe1"/>
        <property name="loginUrl" value="/login"/>
        <property name="successUrl" value="/"/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value = "/login" />
        <property name="successUrl" value = "/"  />
        <property name="unauthorizedUrl" value = "/unauthorize"/>
<property name="filters">
            <map>
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </map>
        </property>
<property name="filterChainDefinitions">
            <value>
                /static/**=anon
                /login=authc
                /logout=logout
                /unauthorize=authc
                /**=user,perms <
            </value>
        </property>
</bean>

登录页面提交后,跳转到 /login,进入登录方法,由于此路径权限设置为authc,shiro对该路径进行过滤,authc权限由FormAuthenticationFilter进行过滤。登录请求进入onAccessDenied方法

protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) {  //判断是否是登录请求
            if (isLoginSubmission(request, response)) { // 是否是http post请求
                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.");
                }
                //allow them to see the login page ;)
                return true;
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }
            saveRequestAndRedirectToLogin(request, response);
            return false;
        }
}

其中 executeLogin(request, response)方法的具体实现在继承的AuthenticatingFilter里

protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        AuthenticationToken token = createToken(request, response); 
        if (token == null) {
            String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +"must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }
        try {
            Subject subject = getSubject(request, response);
            subject.login(token);
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            return onLoginFailure(token, e, request, response);
        }
}

剖析:createToken(request, response); 具体实现在子类FormAuthenticationFilter中

protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
    String username = getUsername(request);
    String password = getPassword(request);
    return createToken(username, password, request, response);
}



从上可以看出,具体的登录账号和密码从request中取出来,并创建了token对象,调用subject的login方法,login方法实现大致流程是用token去realm中取AuthenticationInfo对象,AuthenticationInfo对象存放的是正确的登录账号和密码,并和token中数据进行匹配,然后根据匹配情况返回相应的结果。realm中方法需自己实现,大致流程:从token中取出用户登录填写的账号,去查找正确的登录信息,若是查找不到,返回null,如果查找到对应的登录账号和密码,则封装到AuthenticationInfo对象中,并返回该对象。
java代码:
@RequestMapping(value = "/login")
public String toLogin(HttpServletRequest request, Model model){
        String exceptionClassName = (String)request.getAttribute("shiroLoginFailure");
        String error = null;
        if(UnknownAccountException.class.getName().equals(exceptionClassName)) {
            error = "用户名/密码错误";
        } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
            error = "用户名/密码错误";
        } else if(exceptionClassName != null) {
            error = "其他错误:" + exceptionClassName;
        }
        model.addAttribute("error", error);
        return "login";  // 跳转到登录页面
}
2、自定义登录实现
最关键的是在shiro配置中,登录提交的url需设置为不过滤处理,如提交到/login,则/login=anon,
方法中可实现自己的登录验证逻辑。若是账号密码匹配工作仍要shiro来完成,则将用户填写的账号和密码封装到token对象中,调用subject的login方法。
代码示例:
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
       try {
            subject.login(token);
        } catch (UnknownAccountException ua){
            returnInfo.setMessage("用户名错误");
        } catch (IncorrectCredentialsException ic){
            returnInfo.setMessage("密码错误");
        }
   }

附:

1)shiro默认注册的filters

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
}

2)登录异常

UnknownAccountException(账号不存在)
IncorrectCredentialsException(密码错误)
DisabledAccountException(帐号被禁用)
LockedAccountException(帐号被锁定)
ExcessiveAttemptsException(登录失败次数过多)
ExpiredCredentialsException(凭证过期)等
 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值