Site Overlay

基于WebFlux过滤器与Themleaf的登陆权限验证

需求:

后台管理系统的数据修改部分需要一个简易的进行登陆权限验证

原本可以的话打算用的是shrio框架进行权限管理,但是shrio框架是因为需要对HttpServletRequest进行配置相关参数,而当前使用的WebFlux并没有servlet,所以直接没法使用shrio。所以只有自己写一个基于过滤器的建议权限框架。

主要有五个过滤流程:

  1. 判断是不是需要权限的uri存在/admin之后的页面,以及获取静态资源不进行拦截直接放行
  2. 判断cookie中是否存在一个token的cookie,如果没有的话则跳转到“/admin/login/“,并且在后面附带上最开始点击的页面,用于之后 登录 成功后直接进入该页面,不用重新点击。
  3. 如果有名为token的cookie,取出来,验证该token,是否是对应的正确的管理员用户,如果没有跳转到“/admin/login/“,附带访问页面,理由同上第二条。
  4. 如果存在该用户,判断该用户登录最后登陆时间是否超过了所限制的时间,如果超过,也跳转回登录页面重新登录
  5. 以上四个过滤全部通过的话就说明是已登录的有效用户,放行。

过滤器:

import com.miracle.qaodo.dao.ManagerUserRedisDao;
import com.miracle.qaodo.entity.ManagerUser;
import com.miracle.qaodo.util.ServerTimer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.net.URI;

/**
 * @Author Diuut
 * @Date 2020/11/5  15:54
 */
@Configuration
@Order(0)//数字越小越优先
@Slf4j
public class AdminWebFilter implements WebFilter {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private ManagerUserRedisDao managerUserRedisDao;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        URI uri = request.getURI();
        log.info("uri:{}", uri);
        if (!uri.getPath().contains("/admin") || uri.getPath().contains("/static")
                || uri.getPath().contains(".css") || uri.getPath().contains(".js")
                || uri.getPath().contains(".jpg") || uri.getPath().contains(".ico")
                || uri.getPath().contains(".png")) {
            return chain.filter(exchange);
        }
        log.info("------AdminWebFilter-----");
        HttpCookie cookie = exchange.getRequest().getCookies().getFirst("token");
        String token = "";
        if (cookie != null) {
            token = cookie.getValue();
        }
        log.info("token:{}", token);
        String path = uri.getPath();
        String newPath = path.replace("/", "_");
        if (StringUtils.isEmpty(token) && uri.getPath().contains("/admin")) {
            log.info("登陆信息token为空");
            ServerHttpRequest authErrorReq = request.mutate().path("/admin/login/" + newPath).build();
            ServerWebExchange authErrorExchange = exchange.mutate().request(authErrorReq).build();
            return chain.filter(authErrorExchange);
        }
        ManagerUser managerUser = managerUserRedisDao.getOneByToken(token);
        log.info("managerUser:{}", managerUser);
        if (managerUser == null) {
            log.info("未登录,无权进行该操作");
            ServerHttpRequest authErrorReq = request.mutate().path("/admin/login/" + newPath).build();
            ServerWebExchange authErrorExchange = exchange.mutate().request(authErrorReq).build();
            return chain.filter(authErrorExchange);
        }
        int nowSec = ServerTimer.distOfSecond();
        int lastTime = managerUser.getLastTime();
        log.info("nowSec:{} ,lastTime:{}", nowSec, lastTime);
        if (nowSec - lastTime > 3600) {  //超时时间秒数
            log.info("登录超时重新登录");
            ServerHttpRequest authErrorReq = request.mutate().path("/admin/login/" + newPath).build();
            ServerWebExchange authErrorExchange = exchange.mutate().request(authErrorReq).build();
            return chain.filter(authErrorExchange);
        }
        return chain.filter(exchange);
    }
}

Controller层

    @Autowired
    private ManagerUserDao managerUserDao;

    @RequestMapping("/loginform")
    public String loginform(@RequestParam(value = "username") String username
            , @RequestParam(value = "password") String password
            , @RequestParam(value = "uri") String uri
            , ServerWebExchange exchange, Model model) {
        log.info("username:{},password:{},uri:{}", username, password, uri);
        String reluri = uri.replace("_", "/");
        String res = thymeleafService.managerUserLogin(username, password);

        if (!res.contains("token")) {
            log.info("manager==null");
            model.addAttribute("info", new Dson().put("value", res)._Value());
            model.addAttribute("uri", new Dson().put("value", reluri)._Value());
            return "admin/login";
        }
        String[] tokenSplit = res.split("=");
        ResponseCookie cookie = ResponseCookie.from("token", tokenSplit[1]).build();
        exchange.getResponse().addCookie(cookie);
        Object result = thymeleafService.indexdata();

        model.addAttribute("result", result);

        return "redirect:" + reluri;
    }

    @RequestMapping("/admin/login/{uri}")
    public String login(Model model, @PathVariable("uri") String uri) {
        model.addAttribute("info", new Dson().put("value", "      ")._Value());
        model.addAttribute("uri", new Dson().put("value", uri)._Value());
        return "admin/login";
    }

Service层

  /**
     * 管理员登录
     *
     * @param username 用户名
     * @param password 用户密码
     * @return token
     */
    public String managerUserLogin(String username, String password) {
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return "账号或密码为空";
        }
        ManagerUser managerUser = managerUserRedisDao.getOneByUsername(username);
        if (managerUser == null) {
            return "用户名或密码有误";
        }
        if (!StringUtils.pathEquals(managerUser.getPassword(), password)) {
            return "用户名或密码有误";
        }
        String tokenMD5 = chessService.tokenMD5(username, password);
        managerUser.setToken(tokenMD5);
        managerUser.setLastTime(ServerTimer.distOfSecond());
        managerUser.setLastTimeStr(ServerTimer.getFullWithS());
        managerUserRedisDao.save(managerUser);
        return "token=" + tokenMD5;
    }

登陆页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
    <title>Login Form</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="../../static/css/loginstyle.css" rel='stylesheet' type='text/css'/>
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div class="main">
    <div class="login">
        <h1>巧多后台数据管理</h1>
        <div class="inset">
            <!--start-main-->
            <form name="myForm" id="myForm" action="/loginform" method="get" >
                <div>
                    <h2>管理员登录</h2>
                    <h4 th:text="${info.value}" style="text-align: center;color: #e54d42"></h4>
                    <input type="hidden" th:value="${uri.value}" name="uri">
                    <span><label>用户名</label></span>
                    <span><input type="text" class="textbox" name="username"></span>
                </div>
                <div>
                    <span><label>密码</label></span>
                    <span><input type="password" class="password" name="password"></span>
                </div>
                <div class="sign">
                    <input type="submit" value="登录" class="submit" onclick="submitForm()"/>
                </div>
            </form>
        </div>
    </div>
    <!--//end-main-->
</div>
</body>
</html>

各种跳转是基于现有的跳转习惯进行修改的,未登录直接进入登陆,登陆失败也会通过themleaf预留的的info值进行显示原因。

发表回复

您的电子邮箱地址不会被公开。

A beliving heart is your magic My heart
欢迎来到Diuut的个人博客,这里是我的一些零零碎碎的知识汇总,希望有能帮到你的内容。 | 蜀ICP备2021011635号-1 | Copyright © 2024 Diuut. All Rights Reserved.