登錄綜合案例01,前端使用vue+elementui+axios 后端 springboot+mybatis-plus+swagger2
- 前端使用vue+elementui+axios
- 進入可視化界面創建新專案
- 開始作業
- 新建login.vue的js
- 設計登錄頁面
- 登陸時的表單校驗
- 表單校驗的代碼
- 校驗的代碼
- 重置表單
- 登陸后臺介面
- 前端呼叫后端介面
- 完成在密碼框回車即登錄
- 完善登陸功能
- 后端LoginController介面方法改動
- 后端UserServiceImpl方法改動
- 前臺登錄的方法改動
- 路由守衛(只放行login)
- 在main.js中添加路由守衛的代碼:
- 設定請求頭的值----請求攔截器
- 引入shiro安全框架
- 測驗介面的swagger2路徑
- 登錄成功頁面的布局
- 退出的js方法
- 解決瀏覽器回退按鈕清空token
- UserServiceImpl退出代碼
前端使用vue+elementui+axios
進入可視化界面創建新專案

開始作業
注意:
(1) App.vue中必須要加路由渲染
(2)在index.js中配置login.vue的路徑
{
path: '/login',
name: 'Login',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/login.vue')
}
新建login.vue的js
export default 只能匯出一個默認模塊
<script>
export default {
name: "login"
}
</script>
注意:如果從git上下載專案,就要執行以下命令

設計登錄頁面
(1)login.vue組件頁面
<template>
<!-- 登錄的容器-->
<div class="login_container">
登錄頁面
</div>
</template>
(2) 設定登陸界面的css樣式
<style scoped>
.login_container{
background-color: #e2a5b9;
height: 100%;
}
</style>
(3)發現.login_container高度無效, 在assets下創建一個全域的css
body,html,#app{
height: 100%;
padding: 0;
margin: 0;
font-size: 12px;
}

(4)注意:一定要把全域css匯入main.js 使用需要的插件,作用:加載公共組件
//匯入全域css
import './assets/css/global.css'
(5)登陸框和登陸框的頭像設計布局
<template>
<!-- 登錄的容器-->
<div class="login_container">
<!-- 登錄盒子 -->
<div class="login_box">
<!-- 頭像 -->
<div class="avatar_box">
<img src="../assets/dog.png" alt="">
</div>
<!-- 登錄表單 -->
</div>
</div>
</template>
(6)css樣式
<style scoped>
.login_container{
background-color: #2b5b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background: #fff;
border-radius: 3px;
/**絕對定位*/
position: absolute;
/**左偏移*/
left: 50%;
/**上偏移*/
top: 50%;
/**減去容器自身的寬高*/
transform: translate(-50%, -50%);
}
.login_box>.avatar_box{
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 5px;
/**陰影*/
box-shadow: 0 0 10px #ddd;
/**絕對定位*/
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: pink;
}
.login_box>.avatar_box>img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
</style>
(7)設計表單輸入框
<template>
<!-- 登錄的容器-->
<div class="login_container">
<!-- 登錄盒子 -->
<div class="login_box">
<!-- 頭像 -->
<div class="avatar_box">
<img src="../assets/dog.png" alt="">
</div>
<!-- 登錄表單 -->
<div style="margin: 20px;"></div>
<el-form class="login_form" >
<el-form-item >
<el-input prefix-icon="el-icon-user" placeholder="請輸入用戶名" v-model="loginFormData.loginName" ></el-input>
</el-form-item>
<el-form-item >
<el-input prefix-icon="el-icon-lock" placeholder="請輸入密碼" v-model="loginFormData.password"></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button type="primary" >提交</el-button>
<el-button>重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
(8)表單的css
/*表單的設計*/
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
登陸時的表單校驗
(1)在表單元素上添加 :rules=“myRules”
(2)在data中定義校驗規則:
data(){
return {
myRules:{
}
}
}
(3)在表單元素上使用指定的校驗規則
注意:如果vue表單輸入的有資料,但是提示不能為空,檢查以下
第一個地方是el-form標簽是否系結了值,也就是:model=""
第二個地方是el-form標簽是否系結了表單驗證規則,也就是:rules=""
第三個地方是el-form-item標簽是否有prop,并且prop的值是否和rules的值對應
注意:如果表單輸入不上值,一定要把表單中的:model屬性改為v-model


表單校驗的代碼
<!-- 登錄表單 -->
<div style="margin: 20px;"></div>
<!-- 添加校驗規則第一步添加:rules="loginRules" 表單的校驗規則-->
<el-form class="login_form" :model="loginFormData" :rules="LoginRules">
<!-- 第二步加上prop這個屬性 表示使用表單中的那個校驗規則-->
<el-form-item prop="loginName">
<!-- 第三步注意prop的屬性值是否與每個輸入框里面的v-model的屬性是否對照-->
<el-input prefix-icon="el-icon-user" placeholder="請輸入用戶名" v-model="loginFormData.loginName" ></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input prefix-icon="el-icon-lock" placeholder="請輸入密碼" v-model="loginFormData.password"></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button type="primary" >提交</el-button>
<el-button>重置</el-button>
</el-form-item>
</el-form>
校驗的代碼
<script>
export default {
name: "login",
data(){
return {
loginFormData:{
loginName:"",
password:"",
},
//定義登錄的校驗規則
LoginRules:{
loginName:[
{ required: true, message: '用戶名不能為空', trigger: 'blur' },
{ min: 3, max: 5, message: '長度在 3 到 5 個字符', trigger: 'blur' }
],
password:[
{ required: true, message: '密碼不能為空', trigger: 'blur' },
{ min: 6, max: 8, message: '長度在 6到 8 個字符', trigger: 'blur' }
]
}
}
}
}
</script>
重置表單
(1)為表單添加一個屬性 ref=“名稱”

(2)重置的陳述句 loginFormRef是指ref的值
this.$refs.loginFormRef.resetFields();
重置的方法:
methods: {
//重置方法
loginReset() {
console.log(this);
this.$refs.loginFormRef.resetFields();
},
}
登陸后臺介面
(1)依賴
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zz</groupId>
<artifactId>springboot-vue</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-vue</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mybatis-plus/依賴-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- mybatis-plus-generator代碼生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 模板引擎 依賴,-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- druid資料源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<!-- swagger2-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>
<!-- swagger 好看的ui-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<!-- 引入shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2)mp代碼生成器
package com.zz.springbootvue01;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
// 演示例子,執行 main 方法控制臺輸入模塊表名回車自動生成對應專案目錄中
public class CodeGenerator {
/**
* <p>
* 讀取控制臺內容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("請輸入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("請輸入正確的" + tip + "!");
}
public static void main(String[] args) {
// 代碼生成器
AutoGenerator mpg = new AutoGenerator();
// 全域配置
GlobalConfig gc = new GlobalConfig();
// 獲取工程的根目錄
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");//
gc.setAuthor("張崢");
gc.setOpen(false);//是否生成代碼后打開本地目錄
gc.setSwagger2(true); //是否生存物體屬性 Swagger2 注解
gc.setServiceName("%sService"); //service命名
gc.setMapperName("%sDao"); //Dao命名
//
mpg.setGlobalConfig(gc);//是否設定全域配置
// 資料源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/springboot_vue?serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("aaa");//模塊名
pc.setParent("com.zz");//設定父包 com.zz.aaa.controller dao service entity
// 設定dao
pc.setMapper("dao");
mpg.setPackageInfo(pc);
// 自定義配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 velocity
String templatePath = "/templates/mapper.xml.vm";
// 自定義輸出配置
List<FileOutConfig> focList = new ArrayList<>();
// 預計目錄 mapper/aaa/UserMapper.xml
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定義輸出檔案名 , 如果你 Entity 設定了前后綴、此處注意 xml 的名稱會跟著發生變化!!
return projectPath + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
//關閉系統模板引擎
templateConfig.setXml(null);
//放入空的模板引擎替換掉默認的模板引擎
mpg.setTemplate(templateConfig);
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);//是否采用駝峰命名
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//列是否要駝峰命名
strategy.setEntityLombokModel(true);// 是否要lombok
// 是否要前綴
strategy.setTablePrefix("acl_");
strategy.setRestControllerStyle(true);//controller是否使用restful風格
mpg.setStrategy(strategy);
mpg.execute();
}
}
(3)swagger2的配置,注意要更改在哪個包下生產api檔案
.apis(RequestHandlerSelectors.basePackage(“com.zz.aaa.controller”))
@Configuration//配置類
public class SwaggerConfig {
// swagger2的是實體物件Docket
@Bean
public Docket getDocket() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("Qy129")
.apiInfo(apiInfo())
.select()
// 設定哪些包下的類生產api檔案
.apis(RequestHandlerSelectors.basePackage("com.zz.aaa.controller"))
// 設定哪些請求路徑生產介面檔案
.paths(PathSelectors.any())
.build();
return docket;
}
private ApiInfo apiInfo() {
Contact DEFAULT_CONTACT = new Contact("張崢", "http://www.jd.com", "2300326070@qq.com");
ApiInfo apiInfo = new ApiInfo("管理系統api介面", "管理系統api介面", "2.0", "http://www.baidu.com",
DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList<VendorExtension>());
return apiInfo;
}
}
(4)主啟動類
package com.zz.springbootvue01;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
@EnableSwagger2//開始awagger2注解
@MapperScan("com.zz.aaa.dao")//掃描dao層
public class SpringbootVue01Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootVue01Application.class, args);
}
}
注意:在主實作類上開啟swagger2的注解和包掃描的注解
@EnableSwagger2//開啟swagger2的注解
@MapperScan(“com.zz.aaa.dao”)//掃描dao層
(5)application.yml的配置資訊
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_vue?serverTimezone=Asia/Shanghai
username: root
password: root
server:
port: 8081
logging:
level:
com.zz.aaa.dao: debug
(6)LoginController層登錄介面代碼
package com.zz.aaa.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zz.aaa.entity.User;
import com.zz.aaa.vo.CommonResult;
import com.zz.aaa.vo.LoginVo;
import com.zz.aaa.service.UserService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author : 小崢
* @date : 2021/5/2 22:28
* @description:
*/
@RestController
@Api("登錄介面API")
@RequestMapping("/aaa/login")
public class LoginController {
@Resource
private UserService userService;
/**
* 登錄的介面
* @return
*/
@PostMapping("login")//LoginVo用來接收登陸者的資訊
public CommonResult login(LoginVo loginVo) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", loginVo.getLoginName());
wrapper.eq("password", loginVo.getPassword());
User user = userService.getOne(wrapper);
if (user != null) {
return new CommonResult(2000, "登錄成功", user);
} else {
return new CommonResult(5000, "登錄失敗", null);
}
}
}
CommonResult 物體類
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("回應的物件")
public class CommonResult {
@ApiModelProperty("回應的狀態碼")
private Integer code;
@ApiModelProperty("回應的資訊")
private String msg;
@ApiModelProperty("回應的資料")
private Object result;
}
接收登陸者的資訊LoginVo物體類
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("登錄的物件")
public class LoginVo {
@ApiModelProperty(value = "賬戶")
private String loginName;
@ApiModelProperty(value = "密碼")
private String password;
}
前端呼叫后端介面
(1)在main.js中引入axios并掛載到Vue物件上
import axios from 'axios'
//把axios掛載到vue物件
Vue.prototype.$http=axios;
(2)登錄頁面ajax請求登錄成功跳轉home.vue頁面,這里一定要先表單驗證成功后在進行ajax操作
這里的官網上的foemName是指表單上ref="名稱"的值

//登錄的ajax
submit() {
var that=this;
this.$refs.loginFormRef.validate((valid) => {
//表單驗證成功后
if (valid) {
this.$http.post("http://localhost:8081/aaa/login/login", this.loginFormData).then(function (dataInfo) {
// console.log(dataInfo)
if (dataInfo.data.code === 2000) {
//顯示登錄成功
that.$message.success(dataInfo.data.msg);
// 并且跳轉頁面
that.$router.push("/home");
} else {
console.log(dataInfo.data.msg)
that.$message.error(dataInfo.data.msg);
}
})
}
});
}
(3)以下表示出現跨域問題
什么情況下會出現跨域問題?
(1)必須是ajax請求
(2)從一個區域請求另一個區域,協議不同或者ip不同或者埠號不同,
解決:只需要在后臺LoginController頁面加上注解**@CrossOrigin**


(4)注入home.vue組件
①創建home.vue組件
②在index.js中注冊home.vue組件
{
path: '/home',
name: 'Home',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/home.vue')
}
完成在密碼框回車即登錄
(1)在表單上添加 @submit.native.prevent
(2)在密碼框上添加 @keyup.enter.native.prevent=“submit()”
添加回車觸發登錄的方法 這里的submit()表示登錄的方法,

完善登陸功能
(1)登錄成功后,前端要保存登錄這的資訊
保存在sessionStorage.setItem(key,value)
sessionStorage在當前視窗有效
localStorage再新開一個視窗也有效,關閉瀏覽器無效
(2)登錄成功后,后端也會保存登錄者的資訊
保存在redis中,并且會隨機產生一個key,value為用戶的資訊,并且把key相應給前端,
注意要先把redis的配置添加到application.yml
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///springboot_vue?serverTimezone=Asia/Shanghai
username: root
password: root
redis:
host: 127.0.0.1
port: 6379
server:
port: 8081
logging:
level:
com.zz.dao: debug
后端LoginController介面方法改動
@PostMapping("login")
private CommonResult login(@ApiParam("登錄者資訊") @RequestBody LoginVo loginVo) {
return userService.findByNameAndPassword(loginVo);
}
后端UserServiceImpl方法改動
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
@Resource
private UserDao userDao;
@Resource
private RedisTemplate redisTemplate;
@Override
public CommonResult findByNameAndPassword(LoginVo loginVo) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", loginVo.getLoginName());
wrapper.eq("password", loginVo.getPassword());
User user = userDao.selectOne(wrapper);
if (user!= null) {
// 登錄成功就把用戶的資訊保存到redis
// 隨機產生一個key
String key = UUID.randomUUID().toString().replace("-", "");
// 把隨機產生的key作為key,用戶的資訊當做value
redisTemplate.opsForValue().set(key,user,24, TimeUnit.HOURS);
return new CommonResult(2000, "登錄成功", key);
} else {
return new CommonResult(5000, "登錄失敗", null);
}
}
}
前臺登錄的方法改動
//登錄的ajax
submit() {
var that=this;
this.$refs.loginFormRef.validate((valid) => {
//表單驗證成功后
if (valid) {
this.$http.post("http://localhost:8081/aaa/login/login", this.loginFormData).then(function (dataInfo) {
if (dataInfo.data.code === 2000) {
//顯示登錄成功
that.$message.success(dataInfo.data.msg);
// 把用戶的key保存起來 sessionStorage localStorage 本地
// console.log(dataInfo.data.result)
sessionStorage.setItem("token",dataInfo.data.result);
// 并且跳轉頁面
that.$router.push("/home");
} else {
console.log(dataInfo.data.msg)
that.$message.error(dataInfo.data.msg);
}
})
}
});
}
路由守衛(只放行login)

在main.js中添加路由守衛的代碼:
//to:路由跳轉的路徑
//from:從哪跳轉來的
//next:執行
router.beforeEach((to,from,next)=>{
var path=to.path;
if (path==="/login"){//如果跳轉路徑為login則放行
return next();
}
// 判斷是否攜帶token值
var token=sessionStorage.getItem("token");
if (token){
return next();//已經登錄則放行
}
return next("/login");
})

設定請求頭的值----請求攔截器
在main.js中添加,要放在掛載vue物件的上面
//axios請求攔截器
axios.interceptors.request.use(config=>{
var token = sessionStorage.getItem("token");
if (token){
config.headers.token=token;
}
return config;
})

引入shiro安全框架
(1)引入依賴
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
(2)引入ShiroConfig配置類,注意:這里還需要放行swagger的相關路徑
如果加了@CrossOrigin跨域注解,前臺訪問還是報錯跨域問題,則查看訪問的路徑是否放行,或是否有權限 等原因都會導致跨域
一定要放行登錄的路徑退出的路徑
package com.zz.aaa.config;
import com.zz.aaa.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.Filter;
import java.util.HashMap;
@Configuration
public class ShiroConfig {
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(Realm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
// IOC控制反轉 DI依賴注入
@Bean(value = "myRealm")
public Realm getRealm(CredentialsMatcher credentialsMatcher) {
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher);
return myRealm;
}
@Bean(value = "credentialsMatcher")
public CredentialsMatcher getCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashIterations(1024);
credentialsMatcher.setHashAlgorithmName("MD5");
return credentialsMatcher;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//重點 shiro 不配置登錄頁面 會默認跳轉到login.jsp
HashMap<String, String> map = new HashMap<>();
map.put("/aaa/login/login", "anon");
map.put("/aaa/login/exit", "anon");
// 這里還需要放行swagger的相關路徑
map.put("/doc.html","anon"); //anon表示放行
map.put("/webjars/**","anon"); //anon表示放行
map.put("/swagger-resources/**","anon"); //anon表示放行
map.put("/v2/**","anon"); //anon表示放行
map.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
// 注冊filter組件
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setName("shiroFilter");
filterRegistrationBean.setFilter(new DelegatingFilterProxy());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
(3)引入MyRealm
package com.zz.aaa.realm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zz.aaa.entity.User;
import com.zz.aaa.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import javax.annotation.Resource;
public class MyRealm extends AuthorizingRealm {
@Resource
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// User user = (User) principalCollection.getPrimaryPrincipal();
// List<String> permissions = userService.findPermissionByUserid(user.getUserid());
// SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// if (permissions.size()>0){
// info.addStringPermissions(permissions);
// }
// return info;
return null;
}
/**
* 登錄認證
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 獲取用戶的用戶名
String username = authenticationToken.getPrincipal().toString();
// 根據用戶名獲取用戶
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
User user = userService.getOne(wrapper);
if (user!=null){
// 獲得鹽
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), salt, this.getName());
return info;
}
return null;
}
}
(4)UserServiceImpl類,service的代碼
@Service
@Slf4j//列印日志
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
@Resource
private UserDao userDao;
@Resource
private RedisTemplate redisTemplate;
@Override
public CommonResult findByNameAndPassword(LoginVo loginVo) {
try {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getLoginName(),loginVo.getPassword());
subject.login(token);
// 獲得登錄的資訊
Object user = subject.getPrincipal();
// 登錄成功就把用戶的資訊保存到redis
// 隨機產生一個key
String key = UUID.randomUUID().toString().replace("-", "");
// 把隨機產生的key作為key,用戶的資訊當做value
redisTemplate.opsForValue().set(key,user,24,TimeUnit.HOURS);
return new CommonResult(2000, "登錄成功", key);
} catch (AuthenticationException e) {
e.printStackTrace();
return new CommonResult(5000, "登錄失敗", null);
}
}
}
測驗介面的swagger2路徑
http://localhost:8081/doc.html
登錄成功頁面的布局
<template>
<el-container class="home-container">
<el-header>
<div><img src="../assets/dog.png" width="60" alt="">
<span>進入首頁</span>
<el-button type="danger" @click="exit">危險按鈕</el-button>
</div>
</el-header>
<el-container>
<el-aside width="200px">
<el-menu
default-active="2"
class="el-menu-vertical-demo">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span>導航一</span>
</template>
<el-menu-item-group>
<template slot="title">分組一</template>
<el-menu-item index="1-1">選項1</el-menu-item>
<el-menu-item index="1-2">選項2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分組2">
<el-menu-item index="1-3">選項3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title">選項4</template>
<el-menu-item index="1-4-1">選項1</el-menu-item>
</el-submenu>
</el-submenu>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">導航二</span>
</el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">導航三</span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title">導航四</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
退出的js方法
<script>
export default {
name: "home",
methods: {
//退出的方法
exit() {
var that = this;
this.$http.get("http://localhost:8081/aaa/login/exit").then(function (dataInfo) {
//清除sessionStorage
sessionStorage.clear();
that.$router.push("/login");
})
}
}
}
</script>
解決瀏覽器回退按鈕清空token
// 解決瀏覽器回退按鈕清空token
var guanzhu ='http://www.baidu.com';
window.onhashchange = function () {
var that=this;
/* this.$http.get("http://localhost:8888/sys/login/logout").then(function(resp){*/
this.axios.get("http://localhost:8081/aaa/login/exit").then(function(resp){
sessionStorage.clear();
that.$router.push("/login")
});
// location.href = guanzhu+"?s=mRygKs" + (parseInt((parseInt(new Date().getTime() / (100 * 5 * 1)) + '').substring(2)) + 5000);
};
UserServiceImpl退出代碼
@Override
public CommonResult exit() {
// 獲取request物件
HttpServletRequest request = WebUtil.getRequest();
String token = request.getHeader("token");
if ("".equals(token)){
redisTemplate.delete(token);
return new CommonResult(2000,"退出成功",null);
}
return new CommonResult(5000,"退出失敗",null);
}
后續有登錄綜合案例02,權限選單
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/283221.html
標籤:java
上一篇:這個怎么不對啊
