sa-token-quick-login 模块完毕

This commit is contained in:
shengzhang
2021-05-09 19:08:44 +08:00
parent ca2599c528
commit 0a7a8138b3
42 changed files with 1039 additions and 63 deletions

12
sa-token-plugin/.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.factorypath
.idea/

View File

@@ -15,11 +15,13 @@
<artifactId>sa-token-plugin</artifactId>
<description>sa-token plugins</description>
<!-- 所有子模块 -->
<modules>
<module>sa-token-dao-redis</module>
<module>sa-token-dao-redis-jackson</module>
<module>sa-token-spring-aop</module>
<module>sa-token-oauth2</module>
<!-- <module>sa-token-oauth2</module> -->
<module>sa-token-quick-login</module>
</modules>
</project>

View File

@@ -0,0 +1,12 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.factorypath
.idea/

View File

@@ -0,0 +1,40 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-plugin</artifactId>
<version>1.18.0</version>
</parent>
<packaging>jar</packaging>
<name>sa-token-quick-login</name>
<artifactId>sa-token-quick-login</artifactId>
<description>sa-token-quick-login</description>
<dependencies>
<!-- sa-token-spring-boot-starter -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- 视图引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<!-- spring-boot-configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.0.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,92 @@
package cn.dev33.satoken.quick;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.quick.config.SaQuickConfig;
import cn.dev33.satoken.quick.web.SaQuickController;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaTokenConsts;
/**
* 自动注入
*
* @author kong
*
*/
@Configuration
@Import({ SaQuickController.class })
public class SaQuickBean implements WebMvcConfigurer {
/**
* quick-login 配置
*
* @return see note
*/
@Bean
@ConfigurationProperties(prefix = "sa")
public SaQuickConfig getSaQuickConfig() {
return new SaQuickConfig();
}
/**
* 注入quick-login 配置
*
* @param saQuickConfig 配置对象
*/
@Autowired
public void setSaQuickConfig(SaQuickConfig saQuickConfig) {
SaQuickManager.setConfig(saQuickConfig);
}
/**
* 注册 [sa-token全局过滤器]
*
* @return see note
*/
@Bean
@Order(SaTokenConsts.ASSEMBLY_ORDER - 1)
public SaServletFilter getSaServletFilter() {
return new SaServletFilter().
// 拦截路由 & 放行路由
addInclude("/**").addExclude("/favicon.ico", "/saLogin", "/doLogin", "/sa-res/**").
// 认证函数: 每次请求执行
setAuth(r -> {
// System.out.println("---------- 进入sa-token全局认证 -----------");
// 未登录时直接转发到login.html页面
if (SaQuickManager.getConfig().getAuth() && StpUtil.isLogin() == false) {
try {
HttpServletRequest request = SpringMVCUtil.getRequest();
HttpServletResponse response = SpringMVCUtil.getResponse();
request.getRequestDispatcher("/saLogin").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
// 抛出异常,不再继续执行
throw NotLoginException.newInstance(StpUtil.getLoginKey(), "");
}
}).
// 异常处理函数:每次认证函数发生异常时执行此函数
setError(e -> {
// System.out.println("---------- 进入sa-token异常处理 -----------");
return e.getMessage();
});
}
}

View File

@@ -0,0 +1,36 @@
package cn.dev33.satoken.quick;
import cn.dev33.satoken.quick.config.SaQuickConfig;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* SaQuickManager
* @author kong
*
*/
public class SaQuickManager {
/**
* 配置文件 Bean
*/
private static SaQuickConfig config;
public static void setConfig(SaQuickConfig config) {
SaQuickManager.config = config;
// 如果配置了随机密码
if(config.getAuto()) {
config.setName(SaFoxUtil.getRandomString(8));
config.setPwd(SaFoxUtil.getRandomString(8));
}
}
public static SaQuickConfig getConfig() {
if (config == null) {
synchronized (SaQuickManager.class) {
if (config == null) {
setConfig(new SaQuickConfig());
}
}
}
return config;
}
}

View File

@@ -0,0 +1,90 @@
package cn.dev33.satoken.quick.config;
/**
* sa-quick 配置类 Model
*
* @author kong
*
*/
public class SaQuickConfig {
/** 是否开启全局认证 */
private Boolean auth = true;
/** 用户名 */
private String name = "sa";
/** 密码 */
private String pwd = "123456";
/** 是否自动生成一个账号和密码 */
private Boolean auto = false;
/** 登录页面的标题 */
private String title = "Sa-Token 登录";
/** 是否显示底部版权信息 */
private Boolean copr = true;
public Boolean getAuth() {
return auth;
}
public void setAuth(Boolean auth) {
this.auth = auth;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Boolean getAuto() {
return auto;
}
public void setAuto(Boolean auto) {
this.auto = auto;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Boolean getCopr() {
return copr;
}
public void setCopr(Boolean copr) {
this.copr = copr;
}
@Override
public String toString() {
return "SaQuickConfig [auth=" + auth + ", name=" + name + ", pwd=" + pwd + ", auto=" + auto + ", title=" + title
+ ", copr=" + copr + "]";
}
}

View File

@@ -0,0 +1,73 @@
package cn.dev33.satoken.quick.web;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.dev33.satoken.quick.SaQuickManager;
import cn.dev33.satoken.quick.config.SaQuickConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 登录Controller
* @author kong
*
*/
@Controller
public class SaQuickController {
/**
* 进入登录页面
* @param request see note
* @return see note
*/
@GetMapping("/saLogin")
public String saLogin(HttpServletRequest request) {
request.setAttribute("cfg", SaQuickManager.getConfig());
return "sa-login.html";
}
/**
* 登录接口
* @param name 账号
* @param pwd 密码
* @return 是否登录成功
*/
@PostMapping("/doLogin")
@ResponseBody
public Map<String, Object> doLogin(String name, String pwd) {
// 参数完整性校验
if(SaFoxUtil.isEmpty(name) || SaFoxUtil.isEmpty(pwd)) {
return getResult(500, "请输入账号和密码", null);
}
// 密码校验
SaQuickConfig config = SaQuickManager.getConfig();
if(name.equals(config.getName()) && pwd.equals(config.getPwd())) {
StpUtil.setLoginId(config.getName());
return getResult(200, "ok", StpUtil.getTokenInfo());
} else {
// 校验失败
return getResult(500, "账号或密码输入错误", null);
}
}
private Map<String, Object> getResult(int code, String msg, Object data) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", code);
map.put("msg", msg);
map.put("data", data);
return map;
}
}

View File

@@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.quick.SaQuickBean

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
/*! layer mobile-v2.0.0 Web弹层组件 MIT License http://layer.layui.com/mobile By 贤心 */
;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'<h3 style="'+(e?n.title[1]:"")+'">'+(e?n.title[0]:n.title)+"</h3>":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type="1">'+n.btn[0]+"</span>",2===t&&(e='<span no type="0">'+n.btn[1]+"</span>"+e),'<div class="layui-m-layerbtn">'+e+"</div>"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='<i></i><i class="layui-m-layerload"></i><i></i><p>'+(n.content||"")+"</p>"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"<div "+("string"==typeof n.shade?'style="'+n.shade+'"':"")+' class="layui-m-layershade"></div>':"")+'<div class="layui-m-layermain" '+(n.fixed?"":'style="position:static;"')+'><div class="layui-m-layersection"><div class="layui-m-layerchild '+(n.skin?"layui-m-layer-"+n.skin+" ":"")+(n.className?n.className:"")+" "+(n.anim?"layui-m-anim-"+n.anim:"")+'" '+(n.style?'style="'+n.style+'"':"")+">"+l+'<div class="layui-m-layercont">'+n.content+"</div>"+c+"</div></div></div>",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i]("layui-m-layershade")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:"2.0",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a("#"+o[0]+e)[0];n&&(n.innerHTML="",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],"function"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute("index"))}},"function"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf("/")+1);n.getAttribute("merge")||document.head.appendChild(function(){var e=t.createElement("link");return e.href=a+"need/layer.css?2.0",e.type="text/css",e.rel="styleSheet",e.id="layermcss",e}())}()}(window);

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,54 @@
*{margin: 0; padding: 0;}
body{font-family: Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif;}
::-webkit-input-placeholder{color: #ccc;}
/* 视图盒子 */
.view-box{position: relative; width: 100vw; height: 100vh; overflow: hidden;}
/* 背景 EAEFF3 */
.bg-1{height: 50%; background: linear-gradient(to bottom right, #0466c5, #3496F5);}
.bg-2{height: 50%; background-color: #EAEFF3;}
/* 渐变背景 */
.bg-1{
background-size: 500%;
background-image: linear-gradient(125deg,#0466c5,#3496F5,#0466c5,#3496F5,#0466c5,#2496F5);
animation: bganimation 30s infinite;
}
@keyframes bganimation{
0%{background-position: 0% 50%;}
50%{background-position: 100% 50%;}
100%{background-position: 0% 50%;}
}
/* 内容盒子 */
.content-box{position: absolute; width: 100vw; height: 100vh; top: 0px;}
/* 登录盒子 */
/* .login-box{width: 400px; height: 400px; position: absolute; left: calc(50% - 200px); top: calc(50% - 200px); max-width: 90%; } */
.login-box{width: 400px; margin: auto; max-width: 90%; height: 100%;}
.login-box{display: flex; align-items: center; text-align: center;}
/* 表单 */
.from-box{flex: 1; padding: 20px 50px; background-color: #FFF;}
.from-box{border-radius: 1px; box-shadow: 1px 1px 20px #666;}
.from-title{margin-top: 20px; margin-bottom: 30px; text-align: center;}
/* 输入框 */
.from-item{border: 0px #000 solid; margin-bottom: 15px;}
.s-input{width: 100%; line-height: 32px; height: 32px; text-indent: 1em; outline: 0; border: 1px #ccc solid; border-radius: 3px; transition: all 0.2s;}
.s-input{font-size: 12px;}
.s-input:focus{border-color: #409eff}
/* 登录按钮 */
.s-btn{ text-indent: 0; cursor: pointer; background-color: #409EFF; border-color: #409EFF; color: #FFF;}
.s-btn:hover{background-color: #50aEFF;}
/* 重置按钮 */
.reset-box{text-align: left; font-size: 12px;}
.reset-box a{text-decoration: none;}
.reset-box a:hover{text-decoration: underline;}
/* loading框样式 */
.ajax-layer-load.layui-layer-dialog{min-width: 0px !important; background-color: rgba(0,0,0,0.85);}
.ajax-layer-load.layui-layer-dialog .layui-layer-content{padding: 10px 20px 10px 40px; color: #FFF;}
.ajax-layer-load.layui-layer-dialog .layui-layer-content .layui-layer-ico{width: 20px; height: 20px; background-size: 20px 20px; top: 12px; }

View File

@@ -0,0 +1,65 @@
// sa
var sa = {};
// 打开loading
sa.loading = function(msg) {
layer.closeAll(); // 开始前先把所有弹窗关了
return layer.msg(msg, {icon: 16, shade: 0.3, time: 1000 * 20, skin: 'ajax-layer-load' });
};
// 隐藏loading
sa.hideLoading = function() {
layer.closeAll();
};
// ----------------------------------- 登录事件 -----------------------------------
$('.login-btn').click(function(){
sa.loading("正在登录...");
// 开始登录
setTimeout(function() {
$.ajax({
url: "doLogin",
type: "post",
data: {
name: $('[name=name]').val(),
pwd: $('[name=pwd]').val()
},
dataType: 'json',
success: function(res){
console.log('返回数据:', res);
sa.hideLoading();
if(res.code == 200) {
layer.msg('登录成功', {anim: 0, icon: 6 });
setTimeout(function() {
location.reload();
}, 800)
} else {
layer.msg(res.msg, {anim: 6, icon: 2 });
}
},
error: function(xhr, type, errorThrown){
sa.hideLoading();
if(xhr.status == 0){
return layer.alert('无法连接到服务器,请检查网络');
}
return layer.alert("异常:" + JSON.stringify(xhr));
}
});
}, 400);
});
// 绑定回车事件
$('[name=name],[name=pwd]').bind('keypress', function(event){
if(event.keyCode == "13") {
$('.login-btn').click();
}
});
// 输入框获取焦点
$("[name=name]").focus();
// 打印信息
var str = "This page is provided by Sa-Token, Please refer to: " + "http://sa-token.dev33.cn/";
console.log(str);

View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>登录</title>
<meta charset="utf-8">
<base th:href="@{/}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="./sa-res/login.css">
</head>
<body>
<div class="view-box">
<div class="bg-1"></div>
<div class="bg-2"></div>
<div class="content-box">
<div class="login-box">
<div class="from-box">
<h2 class="from-title" th:utext="${cfg.title}"></h2>
<div class="from-item">
<input class="s-input" name="name" placeholder="请输入账号" />
</div>
<div class="from-item">
<input class="s-input" name="pwd" type="password" placeholder="请输入密码" />
</div>
<div class="from-item">
<button class="s-input s-btn login-btn">登录</button>
</div>
<div class="from-item reset-box">
<a href="javascript: location.reload();" >刷新</a>
</div>
</div>
</div>
</div>
<!-- 底部 版权 -->
<div style="position: absolute; bottom: 40px; width: 100%; text-align: center; color: #666;" th:if="${cfg.copr}">
This page is provided by Sa-Token
</div>
</div>
<!-- scripts -->
<script src="./sa-res/jquery.min.js"></script>
<script src="./sa-res/layer/layer.js"></script>
<script src="./sa-res/login.js"></script>
</body>
</html>