前言:

开发工具:IDEA

开发JDK版本:1.8

Maven版本:3.3+

①、maven的主配置settting.xml 文件中,需要配置 jdk 的版本,修改本地仓库默认位置、使用 阿里的远程仓库

②、在IDEA中配置 maven插件

目录

一、创建 SpringBoot项目,项目名为:ruoyi

二、引入依赖

三、登录页面

四、引入验证码

五、引入Shiro框架

六、在shiro中添加 验证码过滤器,完成首页验证码的显示

七、优化 ShiroConfig 权限配置类


一、创建 SpringBoot项目,项目名为:ruoyi

①、使用 Spring Initializr 初始化器创建一个 SpringBoot 项目,项目名为 ruoyi、选中 web模块

②、创建项目包结构:

com.ruoyi.common.constant
com.ruoyi.common.core
com.ruoyi.common.enums
com.ruoyi.common.exception
com.ruoyi.common.utils

com.ruoyi.framework.config
com.ruoyi.framework.shiro
com.ruoyi.framework.util
com.ruoyi.framework.web.service

com.ruoyi.system.domain
com.ruoyi.system.mapper
com.ruoyi.system.service
com.ruoyi.system.service.impl

com.ruoyi.web.controller.system

③、在resources 目录下创建如下文件夹

// 存放 mapper.xml 文件
resources/mapper/system

// 存放 mybatis 配置相关文件
resources/mybatis

// 存放静态资源文件
resources/static

// 存放 模块相关的 html 文件
resources/templates/system

二、引入依赖

本着用什么依赖,引入什么依赖的原则,先引入2个基本依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

补充:引入 thymeleaf 依赖后,当 Controller 层返回的结果是字符串时,SpringBoot才会使用 themeleaf模板引擎解析字符串,返回相应的页面。例如 返回的是 “/system/user/user" 字符串, SpringBoot中对应的页面是:templates/system/user/user.html

三、登录页面

若依项目用到static 文件夹中静态资源,见百度网盘:https://pan.baidu.com/s/1sEe5FzYwEaFza0Mh1T-h4Q   提取码:yl2p

①、先从百度网盘中下载staitc.zip,将里面的内容拷贝到 static 文件夹中

②、编写 login.html 登录页面,即创建文件  templates / login.html, 内容如下:

<!DOCTYPE html>
<html  lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    
    <title>登录若依系统</title>
    <meta name="description" content="若依后台管理框架">
    <link href="../static/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet"/>
    <link href="../static/css/font-awesome.min.css" th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
    <link href="../static/css/style.css" th:href="@{/css/style.css}" rel="stylesheet"/>
    <link href="../static/css/login.min.css" th:href="@{/css/login.min.css}" rel="stylesheet"/>
    <link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=4.0.0}" rel="stylesheet"/>
    <!--[if lt IE 9]>
    <meta http-equiv="refresh" content="0;ie.html" />
    <![endif]-->
    <link rel="shortcut icon" href="../static/favicon.ico" th:href="@{favicon.ico}"/>
    <style type="text/css">label.error { position:inherit;  }</style>
    <script>
        if(window.top!==window.self){window.top.location=window.location};
    </script>
</head>

<body class="signin">

    <div class="signinpanel">
        <div class="row">
            <div class="col-sm-7">
                <div class="signin-info">
                    <div class="logopanel m-b">
                        <h1><img alt="[ 若依 ]" src="../static/ruoyi.png" th:src="@{/ruoyi.png}"></h1>
                    </div>
                    <div class="m-b"></div>
                    <h4>欢迎使用 <strong>若依 后台管理系统</strong></h4>
                    <ul class="m-b">
                        <li><i class="fa fa-arrow-circle-o-right m-r-xs"></i> SpringBoot</li>
                        <li><i class="fa fa-arrow-circle-o-right m-r-xs"></i> Mybatis</li>
                        <li><i class="fa fa-arrow-circle-o-right m-r-xs"></i> Shiro</li>
                        <li><i class="fa fa-arrow-circle-o-right m-r-xs"></i> Thymeleaf</li>
                        <li><i class="fa fa-arrow-circle-o-right m-r-xs"></i> Bootstrap</li>
                    </ul>
                    <strong>还没有账号? <a href="#">立即注册&raquo;</a></strong>
                </div>
            </div>
            <div class="col-sm-5">
                <form id="signupForm">
                    <h4 class="no-margins">登录:</h4>
                    <p class="m-t-md">你若不离不弃,我必生死相依</p>
                    <input type="text"     name="username" class="form-control uname"     placeholder="用户名" value="admin"    />
                    <input type="password" name="password" class="form-control pword"     placeholder="密码"   value="admin123" />
					<div class="row m-t" th:if="${captchaEnabled==true}">
						<div class="col-xs-6">
						    <input type="text" name="validateCode" class="form-control code" placeholder="验证码" maxlength="5" autocomplete="off">
						</div>
						<div class="col-xs-6">
							<a href="javascript:void(0);" title="点击更换验证码">
								<img th:src="@{captcha/captchaImage(type=${captchaType})}" class="imgcode" width="85%"/>
							</a>
						</div>
					</div>
                    <div class="checkbox-custom" th:classappend="${captchaEnabled==false} ? 'm-t'">
				        <input type="checkbox" id="rememberme" name="rememberme"> <label for="rememberme">记住我</label>
				    </div>
                    <button class="btn btn-success btn-block" id="btnSubmit" data-loading="正在验证登录,请稍后...">登录</button>
                </form>
            </div>
        </div>
        <div class="signup-footer">
            <div class="pull-left">
                &copy; 2019 All Rights Reserved. RuoYi <br>
            </div>
        </div>
    </div>
<script th:inline="javascript"> var ctx = [[@{/}]]; var captchaType = [[${captchaType}]]; </script>
<!-- 全局js -->
<script src="../static/js/jquery.min.js" th:src="@{/js/jquery.min.js}"></script>
<script src="../static/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
<!-- 验证插件 -->
<!-- jQuery Validate 插件: 用于做表单校验-->
<script src="../static/ajax/libs/validate/jquery.validate.min.js" th:src="@{/ajax/libs/validate/jquery.validate.min.js}"></script>
<!-- messages_zh.min.js: jQuery Validate提供了中文信息提示包-->
<script src="../static/ajax/libs/validate/messages_zh.min.js" th:src="@{/ajax/libs/validate/messages_zh.min.js}"></script>
<script src="../static/ajax/libs/layer/layer.min.js" th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script src="../static/ajax/libs/blockUI/jquery.blockUI.js" th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.0.0}"></script>
<script src="../static/ruoyi/login.js" th:src="@{/ruoyi/login.js}"></script>
</body>
</html>

补充:

1)、引入  xmlns:th="http://www.thymeleaf.org" 命名空间,这样在 IDEA中 使用  th: 就有提示。

2)、@{请求路径}, 若路径以 / 开头,那么请求地址为 http://localhost:端口号/ 请求路径,

3)、如果请求地址是静态资源,那么SpringBoot 会去默认的4个地方找:

       classpath:/static 、 classpath:/public、  classpath:/resources、classpath:/META-INF/resources

       例如:请求 http://localhost:8080/1.jpg ,那么SpringBoot 默认会去上面这4个地方查找 1.jpg 文件

       当然,也可以在 application.yml 中新增静态资源 :spring.resources.static-locations = “新的静态资源路径”

③、编写Controller ,处理 /login 请求

package com.ruoyi.web.controller.system;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author liangcy
 * @create 2019/10/8 - 18:36
 */
@Controller
public class SysLoginController {

    @GetMapping("/login")
    public String login() {

        return "/login";
    }
}

④、启动 项目,访问登录页面 :http://localhost:8080/login

四、引入验证码

验证码的依赖、配置、以及Controller 层处理验证码请求,详情见上一篇 SpringBoot 验证码:https://blog.csdn.net/u010559460/article/details/102820228

实现效果:

五、引入Shiro框架

此步骤 引入shiro 框架,主要是做一些拦截功能,拦截一些请求,放行一些请求。

例如:拦截验证码请求,放行访问登录页面请求

后面还会 完成 使用 shiro登录认证,授权,登出,记住我、以及与缓存结合使用的功能。

①、引入shiro 依赖

        <!--Shiro核心框架 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!-- Shiro使用Srping框架 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

②、编写shiro 配置类

shiro 配置类为 SpringBoot容器中注入 3 个 bean

Ⅰ、自定义Realm :继承 AuthorizingRealm 类, 重写 doGetAuthorizationInfo(授权)、doGetAuthenticationInfo(登录认证)两个方法

Ⅱ、SecurityManager 安全管理器:将自定义Realm注入到 安全管理器中,此外还可以注入 记住我、缓存管理器、session管理器(这3个功能后面再弄)

Ⅲ、ShiroFilterFactoryBean   Shiro过滤器配置:将安全管理器注入进来,可以配置登录页面,未授权页面、过滤链、过滤器

 

步骤1、新建 自定义Realm (UserRealm.java),内容如下:

package com.ruoyi.framework.shiro.realm;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 *
 * @author liangcy
 * @create 2019/10/9 - 14:20
 */
@Slf4j
public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权代码....");
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("登录认证代码。。。。");
        return null;
    }
}

补充:这里先完成拦截某些请求,放行某些请求,所以 登录认证以及授权相关的代码 暂时不写,等后面连接数据库在补上这部分内容。

步骤2、新建 ShiroConfig 配置类,为容器注入bean

package com.ruoyi.framework.config;

import com.ruoyi.framework.shiro.realm.UserRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 权限配置类
 *
 * @author liangcy
 * @create 2019/10/8 - 22:38
 */
@Configuration
public class ShiroConfig {


    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }

    @Bean
    public SecurityManager securityManager(UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");

        // 权限认证失败,则跳转到指定页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
        // Shiro连接约束配置,即过滤链的定义
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 对静态资源设置匿名访问
        filterChainDefinitionMap.put("/favicon.ico**", "anon");
        filterChainDefinitionMap.put("/ruoyi.png**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/docs/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/ajax/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/ruoyi/**", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        //filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
        // 不需要拦截的访问
        filterChainDefinitionMap.put("/login", "anon");
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();

        shiroFilterFactoryBean.setFilters(filters);
        // 所有请求需要认证
        filterChainDefinitionMap.put("/**", "user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

}

③、启动项目,访问 http://localhost:8080/captcha/captchaImage?type=char

访问过程: 发起请求 -》 shiro 拦截请求 -》发现请求路径是需要登录认证后才能访问的(即请求路径是 非anon的)-》跳转到登录页面,因此在登录页面以及登录页面所需要的静态资源 在shiro中都需要放行,否则连登录页面也是无法访问。

六、在shiro中添加 验证码过滤器,完成首页验证码的显示

让我们把视角拉回到 login.html 页面和 login.js 文件,有关与验证码部分:

点击更换验证码的 js代码:

补充:需要注意到的是 上面的 captchaType 值,应该是从request 域中获取到的值,紧接着会讲到,先把request 设置的 captchaType 的地方截图出来


1)编写 验证码 过滤器类 CaptchaValidateFilter

重写 onPreHandle、isAccessAllowed、onAccessDenied 三个方法

需要注意的是  isAccessAllowed 方法默认先返回 true,否则每次请求都没法通过,从而导致请求无法进入到Controller层。

package com.ruoyi.framework.shiro.web.filter.captcha;

import com.google.code.kaptcha.Constants;
import com.ruoyi.common.constant.ShiroConstants;
import lombok.Data;
import org.apache.shiro.web.filter.AccessControlFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * 验证码 过滤器
 * @author liangcy
 * @create 2019/10/17 - 15:59
 */
@Data
public class CaptchaValidateFilter extends AccessControlFilter {

    //是否开启验证码
    private boolean captchaEnabled = true;

    //验证码类型
    private String captchaType = "math";

    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        request.setAttribute(ShiroConstants.CURRENT_ENABLED, captchaEnabled);
        request.setAttribute(ShiroConstants.CURRENT_TYPE, captchaType);
        return super.onPreHandle(request, response, mappedValue);
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        return true;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        return false;
    }

}

2)在 ShiroConfig 配置类中注入 CaptchaValidateFilter 验证码过滤器对象

 /**
     * 自定义验证码过滤器
     */
    @Bean
    public CaptchaValidateFilter captchaValidateFilter() {
        CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter();
        captchaValidateFilter.setCaptchaEnabled(true);
        captchaValidateFilter.setCaptchaType("char");
        return captchaValidateFilter;
    }

3)修改 ShiroConfig 配置类中的 shiroFilterFactoryBean 方法


4)重启项目,访问登录页面:http://localhost:8080/login

七、优化 ShiroConfig 权限配置类

将 ShiroConfig 类中有些地方用到的字符串提取出来,做成使用 applicaiton.yml 中可以修改的变量

需要修改的地方有:

①、登录页面地址、未授权地址


②、验证码开关、验证码类型(字符串或数字运算)

步骤1、在 ShiroConfig 配置类中添加 4个属性

    //登录地址
    @Value("${shiro.user.loginUrl}")
    private String loginUrl;
    //未授权
    @Value("${shiro.user.unauthorizedUrl}")
    private String unauthorizedUrl;
    //验证码开关
    @Value("${shiro.user.captchaEnabled}")
    private boolean captchaEnabled;
    //验证码类型
    @Value("${shiro.user.captchaType}")
    private String captchaType;

步骤2、在application.yml 文件中设置这些值

# Shiro
shiro:
  user:
    # 登录地址
    loginUrl: /login
    # 权限认证失败地址
    unauthorizedUrl: /unauth
    # 验证码开关
    captchaEnabled: true
    # 验证码类型 math 数字计算 char 字符
    captchaType: math

步骤3、替换 ShiroConfig 类中的常量

步骤4、 通过修改 application.yml 中的值控制是否生成验证码,以及生成字符验证码还是数字运算验证码

Logo

快速构建 Web 应用程序

更多推荐