shiro学习笔记六:shiro认证流程

一、项目说明

项目环境:jdk1.7+tomcat7+idea2018+maven+shiro1.3.2

源代码github地址:https://github.com/tmAlj/shiro/tree/master/ssms

实现目标:完成从前台到控制器,以及自定义realm和logout过滤器的应用等实现整个认证过程

综合实例:基于shiro的按钮级别的权限管理系统

二、认证流程

762d2b7236df706a2eb5f476e3fc133abcf.jpg

三、常用异常

    授权异常:

    (1)UnauthenticatedException :授权异常

    (2)HostUnauthorizedException:没有访问权限

    (3)HostUnauthorizedException:没有访问权限

    (4)AuthorizationException:授权异常父类

    认证异常:

    (1)UnsupportedTokenException:身份令牌异常,不支持的身份令牌

    (2)UnknownAccountException:未知账户/没找到帐号,登录失败

    (3)LockedAccountException:帐号锁定

    (4)DisabledAccountException:账户禁用

    (5)ConcurrentAccessException:用户多次登录异常

    (6)AccountException:账户异常

    (7)ExpiredCredentialsException:过期的凭据异常

    (8)IncorrectCredentialsException:错误的凭据异常

    (9)CredentialsException: 凭据异常

    (10)AuthenticationException:认证的父类

四、Realm类继承关系

5256a443239f51c5f5bc4de2a3b2530ab68.jpg

五、认证流程实现

        注:此节的代码实现是基于shiro学习笔记三:shiro与spring集成实现

(1)创建登录页面login.jsp

        注:使用了bootstrap进行了样式的简单美化,action="shiro/login"地址需要在spring-shiro-config.xml的过滤器中配置/login.jsp=anon

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
    <link rel="stylesheet" type="text/css" href="statics/boostrap/css/bootstrap.css"/>
    <style>
        .tm-container{
            width: 600px;
            margin: 20px auto;
        }
    </style>
</head>
<body>
    <div class="tm-container">
        <form class="form-horizontal" role="form" action="shiro/login" method="post">
            <div class="form-group">
                <label for="firstname" class="col-sm-2 control-label">用户姓名</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="firstname" name="userName" placeholder="请输入姓名">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">用户密码</label>
                <div class="col-sm-10">
                    <input type="password" class="form-control" id="lastname" name="password" placeholder="请输入密码">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="checkbox">
                        <label>
                            <input type="checkbox">请记住我
                        </label>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <button type="submit" class="btn btn-danger">登录</button>
                </div>
            </div>
        </form>
    </div>
    <script type="text/javascript" src="statics/jquery/jquery-3.2.1.js"></script>
    <script type="text/javascript" src="statics/boostrap/js/bootstrap.js"></script>
</body>
</html>

(2)配置登录cotroller

package com.wsd.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * Created by tm on 2018/8/17.
 * shiro认证Controller
 */
@Controller
@RequestMapping("shiro")
public class ShiroController {

    private static final transient Logger log = LoggerFactory.getLogger(ShiroController.class);

    /**
     * 登录
     * @param userName  用户名称
     * @param password  用户密码
     * @return
     */
    @RequestMapping("/login")
    public String login(@RequestParam("userName") String userName, @RequestParam("password") String password){

        // 得到一个Subject对象,该对象为访问系统任意用户
        Subject currentUser = SecurityUtils.getSubject();

        // 通过Subject对象的isAuthenticated判断该用户是否已经验证
        if (!currentUser.isAuthenticated()) {
            // 如果该用户未验证,得到用户的账号和密码,使用UsernamePasswordToken的方式生成一个该用户的token凭证
            UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
            // 开启记住我的功能,这里可以通过获取用户的提交的信息,判断是否选择记住我来决定开启或关闭
            token.setRememberMe(true);
            try {
                // 通过Subject对象的login来验证用户的身份
                currentUser.login(token);
                // 如果用户身份验证不通过会抛出相应的异常,可以通过抛出的异常来设置返回给前台的信息
            } catch (UnknownAccountException uae) {
                // UnknownAccountException账号不存在异常
                log.info("===============账号不存在异常=>"+token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                // IncorrectCredentialsException密码错误异常
                log.info("===============密码错误异常=>"+token.getPrincipal());
            } catch (LockedAccountException lae) {
                // LockedAccountException账户被锁定异常
                log.info("===============账户被锁定异常=>"+token.getPrincipal());
            } catch (AuthenticationException ae) {
                // AuthenticationException即验证不通过异常,为前面几个异常的父类
            }
        }
        //认证成功后跳转,需配置过滤器
        return "redirect:/welcom.jsp";
    }
}

(3)自定义Realm

package com.wsd.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.realm.AuthenticatingRealm;

/**
 * Created by tm on 2018/8/17.
 * 用户自定义认证Realm
 */
public class JdbcRealm extends AuthenticatingRealm {

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //token类型转化
        UsernamePasswordToken upToken = (UsernamePasswordToken)authenticationToken;
        //获取前台用户信息
        String username = upToken.getUsername();
        // TODO 从数据库中获取用户信息,这里先模拟从数据库获取数据

        // 使用数据库中的用户信息与前台传入的用户信息比对,如果用户不存在,抛出异常
        if("wsd".equals(username)) {
            throw new UnknownAccountException("==================用户不存在");
        }
        // 用户被锁定是,抛出异常
        if("wsd1".equals(username)) {
            throw new LockedAccountException("==================用户被锁定");
        }

        // TODO 从数据库中获取用户信息,这里先模拟从数据库获取数据
        Object principal = username;  //从数据中获取用户名称
        Object credentials = "123456";  //从数据中获取用户密码
        String realmName = "jdbcRealm";  //自定义
        return new SimpleAuthenticationInfo(principal, credentials, realmName);
    }
}

(4)在spring-shiro-config.xml配置Realm以及过滤器

<!-- 配置shiro的核心securityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	<property name="cacheManager" ref="cacheManager"/>
	<!--<property name="sessionMode" value="native"/>-->
	<property name="realm" ref="jdbcRealm"/>
</bean>

<!-- 配置shiro的重要的元素Reaml(验证的数据源),可自定义 -->
<bean id="jdbcRealm" class="com.wsd.shiro.JdbcRealm">
</bean>
<property name="filterChainDefinitions">
	<!-- 静态资源需要设置为anon,否则找不到 -->
	<value>
		/statics/** = anon
		/login.jsp = anon
		/welcom.jsp = user
		/logout = logout
	</value>
</property>

(5)退出登录

    说明:需要在退出登录的页面添加<a>标签,指定到退出过滤器匹配的url,同时在shiro配置文件中配置退出过滤器即可。如果不退出登录,返回到login.jsp后输入错误的账户密码仍能访问登录成功的页面。

ba758ddc9b8e51cb03510540bcbcd05bb17.jpg

b25f408fc081778567003232fb90652e62e.jpg

(6)测试举例

    说明:

    (1)由于还没有使用数据库持久化,测试用户的密码在自定义的realm定义为123456,如用wsd和wsd1登录则会在控制台打印出相应的异常

    (2)如果登录成功后进入welcom.jsp,没有点击退出登录按钮,返回到login.jsp输入错误的密码后点击登录仍然可以登录

转载于:https://my.oschina.net/tij/blog/1929793

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值