Jeesite之login模块的从头到尾整合

原文链接:https://blog.csdn.net/weixin_40595244/article/details/80883129

1.sysLogin.jsp

        本文采用从前端到后台的形式,整体的阐述一下jeesite中login模块的交互流程,整个jeesite的重要功能我拟将他分为login,list,权限三个部分,应该包括了我们需要实现的大部分功能,计划将这三个部分逐一写出。

<form id="loginForm"  class="form login-form" action="${ctx}/login" method="post">

整个jsp页面其实就是一个表单,它的主要目的就是接受用户输入的用户名和密码字段,然后交给后台处理。action变量指定了该表达的提交方式,既是交由/a/login所对应的函数来处理。有两个登录页面

sysLogin.jsp 效果图

sysLogin2.jsp 效果图

<input type="text" id="username" name="username" class="required" value="${username}" placeholder="登录名">

<input type="password" id="password" name="password" class="required" placeholder="密码"/>

 以上就是表单里的两个属性,一个属性名为username,一个名为password,表单会借由request属性传到函数当中,届时就能通过getUsername和getPassword两个函数从request中取出。这部分是在FormAuthenticationFilter中的createToken函数中实现,下文中会详细介绍。

        Login模块中的jsp非常简单,难点主要在于shiro的应用上,这也是该模块与普通list模块的区别之处。

2.shiro

只做为jeesite应用来写,更注重在逻辑方面。上回合说到,jsp将username和password打包扔给后台,那么后台是由什么接受呢?在spring-mvc中,负责接受前台数据的是controller部分,而form中所指定的action是/a/login。

@RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET)

public String login(HttpServletRequest request, HttpServletResponse response, Model model) {

    User user = UserUtils.getUser();

    // 如果已经登录,则跳转到管理首页

    if(user.getId() != null){

        return "redirect:"+Global.getAdminPath();

    }

    return "modules/sys/sysLogin";

}

@RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST)

public String login(@RequestParam(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM) String username, HttpServletRequest request, HttpServletResponse response, Model model) {

    User user = UserUtils.getUser();

    // 如果已经登录,则跳转到管理首页

    if(user.getId() != null){

        return "redirect:"+Global.getAdminPath();

    }

    model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);

    model.addAttribute("isValidateCodeLogin", isValidateCodeLogin(username, true, false));

    return "modules/sys/sysLogin";

}

很容易就能定位到,以上两个函数就是处理form的函数,或者说正常情况下是由这两个函数来处理。但是仔细看这两个函数,并没有进行逻辑处理,只是简单的检查和跳转。这是因为shiro的登陆功能在controller之前加入了一个filter。这个filter被配置在文件spring-context-shiro.xml文件里。

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

    <property name="securityManager" ref="securityManager" />

    <property name="loginUrl" value="${adminPath}/login" />

    <property name="successUrl" value="${adminPath}" />

    <property name="filters">

        <map>

            <entry key="authc" value-ref="formAuthenticationFilter"/>

        </map>

    </property>

    <property name="filterChainDefinitions">

        <value>

            /static/** = anon

            /userfiles/** = anon

            ${adminPath}/login = authc

            ${adminPath}/logout = logout

            ${adminPath}/** = user

        </value>

    </property>

</bean>

 以上就是配置过程最关键的部分。loginuUrl属性所指定的url表示的是所有未通过验证的url所访问的位置,此处就是登录界面;successUrl表示的是成功登陆的url访问的位置,此处就是主页。filters则是配置具体验证方法的位置。在此处,${adminPath}/login = authc指定了/a/login,既登陆页面,所需要的验证权限名为authc,又配置了authc所用的filter为formAuthenticationFilter。
        因此整个逻辑是:如果任何地方未登陆,则访问/a/login页面,而/a/login页面的验证权限中又指定了formAuthenticationFilter做为过滤,如果过滤中验证成功,则访问/a这个主页。所以,login.jsp中的表单信息则首先交由formAuthenticationFilter首先处理。

        再来看formAuthenticationFilter中的处理,需要关注的类主要在com.thinkgem.jeesite.modules.sys.security这个包里。通常FormAuthenticationFilter是主要逻辑管理类,SystemAuthorizingRealm这个类则是数据处理类,相当于DAO。但是直接从代码里没发看出功能,这是因为jeesite中的这两个类都是继承于shiro的类,有很多逻辑并没有在jeesite中实现,所以我并不能贴出全部代码,某些地方只用语言来描述。
        大致来讲,首先表单的request被formAuthenticationFilter接收到,然后传给createToken函数,该函数从request中取出name和password,然后生成自定义的一个token传给SystemAuthorizingRealm中的doGetAuthenticationInfo验证。SystemAuthorizingRealm中有systemService的实例,该实例含有userDAO能取出数据库中的name和password。接着由这两个密码生成SimpleAuthenticationInfo,再由info中的逻辑来验证。以上过程中jeesite实现的代码分别如下:

protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {

    String username = getUsername(request);

    String password = getPassword(request);

    if (password==null){

        password = "";

    }

    boolean rememberMe = isRememberMe(request);

    String host = getHost(request);

    String captcha = getCaptcha(request);

    return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha);

}

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {

    UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

     

    if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){

        // 判断验证码

        Session session = SecurityUtils.getSubject().getSession();

        String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);

        if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){

            throw new CaptchaException("验证码错误.");

        }

    }

    User user = getSystemService().getUserByLoginName(token.getUsername());

    if (user != null) {

        byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));

        return new SimpleAuthenticationInfo(new Principal(user),

                user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());

    } else {

        return null;

    }

}

3.service+dao+entity

        还剩下一些传统SSH的内容,具体就是在doGetAuthenticationInfo中systemService是如何取出数据库里的数据的。
        这部分感觉大家都知道,先空在这里,有必要再补充。

猜你喜欢

转载自blog.csdn.net/WARGON/article/details/82778723
今日推荐