springboot shiro配置验证码登录 thyemeleaf

1.pom.xml

<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

2.login登录页面

<!DOCTYPE html>
<html lang="zh_CN" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <link type="text/css" rel="stylesheet" th:href="@{/AdminLTE/dist/css/adminlte.min.css}">
    <style type="text/css">
        html, body {
            width: 100%;
            height: 100%;
        }

        .input-group > .form-control {
            box-shadow: none;
            background-color: rgba(0, 0, 0, 0.2);
            color: #1fc8e3;
        }

        .input-group-prepend > .input-group-text {
            background-color: rgba(0, 0, 0, 0.2);
            color: #1fc8e3;;
        }

        .card {
            position: relative;
            /*left: 487px;*/
            right: -124%;
            top: 45px;
            -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
            filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
            background-color: rgba(0, 0, 0, 0.2);
        }
    </style>
</head>
<body class="hold-transition login-page">
<!--style="background-image:url(/AdminLTE/dist/img/login.jpg); background-size:contain;"-->
<img src="/AdminLTE/dist/img/login.jpg" width="100%" height="100%" style="z-index:-100;position:absolute;left:0;top:0">
<div class="login-box">
    <div class="login-logo">
        <a href="#"><b>权限管理系统</b></a>
    </div>

    <!--login-logo-->
    <div class="card">
        <div class="card-body login-card-body">
            <form action="" method="post" onsubmit="return check()">
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">账&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;号:</span>
                    </div>
                    <input type="text" class="form-control" id="username" name="username" value="admin" placeholder="账号"
                           autocomplete="off">
                </div>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码:</span>
                    </div>
                    <input type="password" class="form-control" id="password" name="password" value="123456"
                           placeholder="密码">
                </div>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">验证码:</span>
                    </div>
                    <input type="text" class="form-control" id="randomcode" name="randomcode" autocomplete="off">
                    <img th:src="@{/validatecodeServlet}" onclick="random(this)"/>
                </div>
                <div class="row">
                    <div class="col-8">
                        <div class="checkbox icheck">
                            <label style="font-size: 14px; font-weight: normal;color: #1fc8e3">
                                <input type="checkbox">&nbsp;&nbsp;记住我
                            </label>
                        </div>
                    </div>
                    <div class="col-4">
                        <button type="submit" class="btn btn-primary btn-block btn-flat">登&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;录</button>
                    </div>
                </div>
            </form>

        </div>
    </div>
</div>
<!-- jQuery -->
<script type="text/javascript" th:src="@{/AdminLTE/plugins/jquery/jquery.js}"></script>
<!-- Bootstrap 4-->
<script type="text/javascript" th:src="@{/AdminLTE/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script>
<script type="text/javascript" th:src="@{/AdminLTE/plugins/tips/jquery.tips.js}"></script>
<script type="text/javascript" th:src="@{/js/login.js}"></script>
</body>
</html>

3.login.js 验证是否为空

function random(tmp) {
    var pathName = window.document.location.pathname;
    tmp.src = pathName.substring(0, pathName.substr(1).indexOf('/') + 1) + "/validatecodeServlet?rnd=" + Math.random();
}

function check() {
    $("#username").val($("#username").val().trim());
    $("#password").val($("#password").val().trim());
    $("#randomcode").val($("#randomcode").val().trim());
    if ($("#username").val() == "") {
        $("#username").tips({
            side: 2,
            msg: '用户名不能为空',
            bg: '#AE81FF',
            time: 3
        });

        $("#username").focus();
        return false;
    } else {
        $("#username").val(jQuery.trim($('#username').val()));
    }

    if ($("#password").val() == "") {

        $("#password").tips({
            side: 2,
            msg: '密码不能为空',
            bg: '#AE81FF',
            time: 3
        });

        $("#password").focus();
        return false;
    }
    if ($("#randomcode").val() == "") {
        $("#randomcode").tips({
            side: 1,
            msg: '验证码不能为空',
            bg: '#AE81FF',
            time: 3
        });

        $("#randomcode").focus();
        return false;
    }
    return true;
}

4.servlet

package com.wxbd.wb_mine.controller;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

@WebServlet(urlPatterns="/validatecodeServlet")
public class ValidatecodeServlet extends HttpServlet {


    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
        int width = 60;
        int height = 32;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        g.setColor(new Color(0xDCDBD2));
        g.fillRect(0, 0, width, height);
        g.setColor(Color.black);
        g.drawRect(0, 0, width - 1, height - 1);
        Random rdm = new Random();
        String hash1 = Integer.toHexString(rdm.nextInt());
        System.out.println(hash1);
        for (int i = 0; i < 50; i++) {
            int x = rdm.nextInt(width);
            int y = rdm.nextInt(height);
            g.drawOval(x, y, 0, 0);
        }
        String capstr = hash1.substring(0, 4);
        Session session = SecurityUtils.getSubject().getSession();
        //将生成的验证码存入session
        session.setAttribute("validateCode", capstr);
        g.setColor(new Color(53, 61, 255));
        g.setFont(new Font("宋体", Font.PLAIN, 24));
        g.drawString(capstr, 8, 24);
        g.dispose();
        //输出图片
        resp.setContentType("image/jpeg");
        OutputStream strm = resp.getOutputStream();
        ImageIO.write(image, "jpeg", strm);
        strm.close();

    }
}

 @RequestMapping("/login")
    public String login(HttpServletRequest request, Map<String, Object> map) throws Exception {
        System.out.println("HomeController.login()");
        // 登录失败从request中获取shiro处理的异常信息。
        // shiroLoginFailure:就是shiro异常类的全类名.
        //------------------------------------------------
        String exception = (String) request.getAttribute("shiroLoginFailure");
        System.out.println("exception=" + exception);
        String msg = "";
        if (exception != null) {
            if (UnknownAccountException.class.getName().equals(exception)) {
                System.out.println("UnknownAccountException -- > 账号不存在:");
                msg = "UnknownAccountException -- > 账号不存在:";
            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
                System.out.println("IncorrectCredentialsException -- > 密码不正确:");
                msg = "IncorrectCredentialsException -- > 密码不正确:";
            } else if ("kaptchaValidateFailed".equals(exception)) {
                System.out.println("kaptchaValidateFailed -- > 验证码错误");
                msg = "kaptchaValidateFailed -- > 验证码错误";
            } else {
                msg = "else >> " + exception;
                System.out.println("else -- >" + exception);
            }
        }
        map.put("msg", msg);
        // 此方法不处理登录成功,由shiro进行处理
        return "login";

    }

验证码拦截校验

package com.wxbd.wb_mine.filter;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
   

    @Override  //验证码校验拦截
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        // 在这里进行验证码的校验
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        Session session = SecurityUtils.getSubject().getSession();
        // 取出验证码
        String validateCode = (String) session.getAttribute("validateCode");
        // 取出页面的验证码
        // 输入的验证和session中的验证进行对比
        String randomcode = httpServletRequest.getParameter("randomcode");
        if (randomcode != null && validateCode != null && !randomcode.equals(validateCode)) {
            // 如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中
            httpServletRequest.setAttribute("shiroLoginFailure", "kaptchaValidateFailed");//自定义登录异常
            // 拒绝访问,不再校验账号和密码
            return true;
        }
        return super.onAccessDenied(request, response);
    }
}

5.设置验证码拦截权限

@Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
       
        //拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/AdminLTE/**", "anon");
        filterChainDefinitionMap.put("/image/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");//退出
        filterChainDefinitionMap.put("/validatecodeServlet", "anon");//验证码
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        System.out.println("ShiroConfiguration.shirFilter() success");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");

        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

最终成果

猜你喜欢

转载自blog.csdn.net/qq_29009973/article/details/81477899