• 权限系统--前后端分离


    目录

    1.前端使用:

    2.后端使用:

    3.前端页面--登录页面

    3.1.在views下新建一个视图,作为登录的视图

    3.2.在登录试图视图中,写入登录页面需要的代码

    3.2.1.登录页面

    3.2.2.登录页面的数据和方法

    3.2.3.登录页面的样式

    3.2.4.渲染主件

    3.2.5.设置路由

    3.2.6.跳转页面

    3.2.7.运行之后的样子

    3.4.8.登录按钮事件

    4.后端登录接口

    4.1.新建一个springboot工程

    4.2.引入相关的依赖

    4.3.mp的代码生成器

    4.4.运行代码生成器

    4.5.配置application文件

    4.6.配置swagger的工具类

    4.7.创建同一返回的数据信息加swagger的注解

    4.7.创建登录参数的实体类加swagger注解

    4.8.后端登录接口加swagger的注解

    5.登录的bug

    5.1.修改登录接口

    5.1.1.如果在数据库查询到了用户信息,然后将用户信息保存

    5.1.2.将保存的信息给前端

    5.1.3.axios得请求拦截器、

    6.前置路由守卫

    6.1.什么是前置路由守卫

    6.2.前置路由守卫的语法

    6.3.使用前置路由守卫 --在main.js

    7.整合shiro

    7.1.添加shiro依赖

    7.2.shiro得配置类

    7.3.增加一个realm类对象

    7.4.新增一个拦截器

    7.5.修改controller代码

    8.主页得布局

    8.1.前端

    9.退出登录

    9.1.前端

    9.2.后端

    10.查询左侧菜单

    10.2.请求路径

    10.3.controller层

    10.4.service层

    10.5.mapper层

    10.6.seriveimpl业务代码

    10.7.连表



    1.前端使用:

    vue + elementui + axios + css + html

    2.后端使用:

    springboot+mybatis-plus +mybatis+druid+shiro+swagger2+redis

    3.前端页面--登录页面

    3.1.在views下新建一个视图,作为登录的视图

    3.2.在登录试图视图中,写入登录页面需要的代码

    3.2.1.登录页面

    1. <template>
    2. <div id="login_box">
    3. <div class="img_position">
    4. <el-avatar :size="140" :src="imgUrl">el-avatar>
    5. div>
    6. <el-card class="box-card">
    7. <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    8. <el-form-item label="用户名" prop="name">
    9. <el-input type="text" v-model="ruleForm.name" autocomplete="off">el-input>
    10. el-form-item>
    11. <el-form-item label="密码" prop="password">
    12. <el-input type="password" v-model="ruleForm.password" autocomplete="off">el-input>
    13. el-form-item>
    14. <el-form-item>
    15. <el-button type="primary"
    16. size="mini"
    17. :plain="true"
    18. @click="login"
    19. style="margin-left: 100px;width: 100px">登录el-button>
    20. el-form-item>
    21. el-form>
    22. el-card>
    23. div>
    24. template>

    3.2.2.登录页面的数据和方法

    1. <script>
    2. export default {
    3. name: "Login",
    4. data(){
    5. return{
    6. ruleForm: {
    7. name: '',
    8. password: ''
    9. },
    10. rules: {
    11. name: [
    12. {required: true, message:'用户名不能为空', trigger: 'blur'},
    13. ],
    14. password: [
    15. {required: true, message: '密码不能为空', trigger: 'blur'},
    16. ]
    17. },
    18. imgUrl:'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
    19. }
    20. },
    21. methods:{
    22. login(){
    23. this.$refs['ruleForm'].validate((valid) => {
    24. if(valid) {
    25. this.$message.success("登录成功")
    26. } else {
    27. this.$message.error("登录失败")
    28. }
    29. })
    30. }
    31. }
    32. }

    3.2.3.登录页面的样式

    1. <style>
    2. #login_box{
    3. position: relative;
    4. width: 500px;
    5. margin: 250px auto;
    6. }
    7. #login_box div.img_position{
    8. position: absolute;
    9. left: 200px;
    10. top: -70px;
    11. }
    12. .text {
    13. font-size: 14px;
    14. }
    15. .item {
    16. padding: 18px 0;
    17. }
    18. .box-card {
    19. padding: 100px 50px 0 0;
    20. width: 480px;
    21. }
    22. style>

    3.2.4.渲染主件

    
       这个是在app.vue 下渲染的,也就是打开网页默认的页面

     3.2.5.设置路由

    //不管这个路径有没有被访问,一定会导入的网页
    import Login from "../views/Login";
    {
      path:'/login', --路径
      name:'Login', --views下的视图
     component:Login --组件的名称
    }

    打开网页之后输入login或者/login,就会去找路由下的index .js  在里面去找有没有/login的路径,找到之后根据import Login from "../views/Login";这句话,去找views下的视图页面,然后再网页上显示

    3.2.6.跳转页面

    {
      path: "/",
      redirect: "/login"
    }

    刚打开网页的时候上面的网址是http://localhost:8080/#/,显示一片空白,想要登录页面还得输入login或者/login,有点麻烦,而且一打开页面应该是登录页面,不是空白的页面,上面的代码是,一打开页面重定向的login

    3.2.7.运行之后的样子

     3.4.8.登录按钮事件

    我想登录成功之后,跳转到主页面,这个就用到了axios

    [1]//导入axios --在main.js中
    import axios from "axios";


    [2]//把axios挂载到vue对象中,以后在vue中如果使用axios直接可以用$http名称
    Vue.prototype.axios=axios

    方法:

    1. methods:{
    2. login(){
    3. //表单校验
    4. this.$refs['ruleForm'].validate((valid) => {
    5. if(valid){
    6. //url:后端登录接口的路径 this.ruleForm是表单
    7. this.$http.post("http://localhost:8808/user/login",this.ruleForm).then(result=>{
    8. //登录成功之后跳转到主页面--路由跳转
    9. this.$router.push("/home")
    10. });
    11. }
    12. })
    13. }
    14. }

    路由设置

    1. {
    2. path: '/home',
    3. name: '/Home',
    4. component: ()=>import("../views/Home")
    5. }

    4.后端登录接口

    4.1.新建一个springboot工程

     注意:选择版本,要不然会报错--8的版本

    4.2.引入相关的依赖

    1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    3. <modelVersion>4.0.0modelVersion>
    4. <parent>
    5. <groupId>org.springframework.bootgroupId>
    6. <artifactId>spring-boot-starter-parentartifactId>
    7. <version>2.3.12.RELEASEversion>
    8. <relativePath/>
    9. parent>
    10. <groupId>com.guangroupId>
    11. <artifactId>demoartifactId>
    12. <version>0.0.1-SNAPSHOTversion>
    13. <name>mybatis-plus-vuename>
    14. <description>Demo project for Spring Bootdescription>
    15. <properties>
    16. <java.version>1.8java.version>
    17. properties>
    18. <dependencies>
    19. <dependency>
    20. <groupId>com.baomidougroupId>
    21. <artifactId>mybatis-plus-generatorartifactId>
    22. <version>3.5.2version>
    23. dependency>
    24. <dependency>
    25. <groupId>org.freemarkergroupId>
    26. <artifactId>freemarkerartifactId>
    27. <version>2.3.31version>
    28. dependency>
    29. <dependency>
    30. <groupId>com.baomidougroupId>
    31. <artifactId>mybatis-plus-boot-starterartifactId>
    32. <version>3.5.2version>
    33. dependency>
    34. <dependency>
    35. <groupId>com.alibabagroupId>
    36. <artifactId>druid-spring-boot-starterartifactId>
    37. <version>1.2.8version>
    38. dependency>
    39. <dependency>
    40. <groupId>com.github.xiaoymingroupId>
    41. <artifactId>swagger-bootstrap-uiartifactId>
    42. <version>1.9.6version>
    43. dependency>
    44. <dependency>
    45. <groupId>com.spring4allgroupId>
    46. <artifactId>swagger-spring-boot-starterartifactId>
    47. <version>1.9.1.RELEASEversion>
    48. dependency>
    49. <dependency>
    50. <groupId>org.springframework.bootgroupId>
    51. <artifactId>spring-boot-starter-webartifactId>
    52. dependency>
    53. <dependency>
    54. <groupId>org.mybatis.spring.bootgroupId>
    55. <artifactId>mybatis-spring-boot-starterartifactId>
    56. <version>2.2.2version>
    57. dependency>
    58. <dependency>
    59. <groupId>mysqlgroupId>
    60. <artifactId>mysql-connector-javaartifactId>
    61. <scope>runtimescope>
    62. dependency>
    63. <dependency>
    64. <groupId>org.projectlombokgroupId>
    65. <artifactId>lombokartifactId>
    66. <optional>trueoptional>
    67. dependency>
    68. <dependency>
    69. <groupId>org.springframework.bootgroupId>
    70. <artifactId>spring-boot-starter-testartifactId>
    71. <scope>testscope>
    72. dependency>
    73. dependencies>
    74. <build>
    75. <plugins>
    76. <plugin>
    77. <groupId>org.springframework.bootgroupId>
    78. <artifactId>spring-boot-maven-pluginartifactId>
    79. <configuration>
    80. <excludes>
    81. <exclude>
    82. <groupId>org.projectlombokgroupId>
    83. <artifactId>lombokartifactId>
    84. exclude>
    85. excludes>
    86. configuration>
    87. plugin>
    88. plugins>
    89. build>
    90. project>

    4.3.mp的代码生成器

    1. package com.guan.demo;
    2. import com.baomidou.mybatisplus.generator.FastAutoGenerator;
    3. import com.baomidou.mybatisplus.generator.config.OutputFile;
    4. import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    5. import java.util.Collections;
    6. /**
    7. * TODO
    8. *
    9. * @author lenovo
    10. * @version 1.0
    11. * @since 2022-08-08 10:02:23
    12. */
    13. public class Generator {
    14. public static void main(String[] args) {
    15. FastAutoGenerator.create("jdbc:mysql://localhost:3306/day?serverTimezone=Asia/Shanghai", "root", "grt081141" +
    16. "")
    17. .globalConfig(builder -> {
    18. builder.author("guan") // 设置作者
    19. .enableSwagger() // 开启 swagger 模式
    20. .fileOverride() // 覆盖已生成文件
    21. .outputDir(".\\src\\main\\java\\"); // 指定输出目录
    22. })
    23. .packageConfig(builder -> {
    24. builder.parent("com.guan.demo") // 设置父包名
    25. .moduleName("system") // 设置父包模块名
    26. .pathInfo(Collections.singletonMap(OutputFile.xml, "src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
    27. })
    28. .strategyConfig(builder -> {
    29. builder.addInclude("acl_user","acl_role","acl_permission")// 设置需要生成的表名
    30. .addTablePrefix("acl_"); // 设置过滤表前缀
    31. })
    32. .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
    33. .execute();
    34. }
    35. }

    4.4.运行代码生成器

    4.5.配置application文件

    1. #设置端口号--一定要设置端口号,不设置的话,端口号会冲突
    2. server.port=8888
    3. spring.datasource.druid.url=jdbc:mysql://localhost:3306/day?serverTimezone=Asia/Shanghai
    4. spring.datasource.druid.username=root
    5. spring.datasource.druid.password=grt081141
    6. spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
    7. #日志
    8. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

    4.6.配置swagger的工具类

    1. @Configuration //该注解为配置类相当于xml
    2. public class SwaggerConfig {
    3. @Bean
    4. //swagger中所有的功能都封装到了Docket类中
    5. public Docket docket(){
    6. Docket docket=new Docket(DocumentationType.SWAGGER_2)
    7. .groupName("接口文档")
    8. 设置api文档信息
    9. .apiInfo(apiInfo())
    10. //为那个包下的类生成接口文档
    11. .select()
    12. .apis(RequestHandlerSelectors.basePackage("com.guan.demo.system.controller"))
    13. .build();
    14. return docket;
    15. }
    16. //定义自己接口文档信息
    17. public ApiInfo apiInfo(){
    18. //description 描述 description 团队地址 license 企业的名字
    19. Contact DEFAULT_CONTACT = new Contact("哈哈哈", "http://www.bidu.com", "1234@qq.com");
    20. ApiInfo apiInfo=new ApiInfo("亿个小项目", "针对小孩子的", "1.0", "http://www.jd.com", DEFAULT_CONTACT, "牛家企业", "http://www.taobao.com", new ArrayList());
    21. return apiInfo;
    22. }
    23. }

     4.7.创建同一返回的数据信息加swagger的注解

    1. @Data
    2. @NoArgsConstructor
    3. @AllArgsConstructor
    4. @ApiModel("返回同一的信息")
    5. public class CommonResult {
    6. @ApiModelProperty("状态码 2000成功,5000失败")
    7. private int code;
    8. @ApiModelProperty("信息")
    9. private String msg;
    10. @ApiModelProperty("数据")
    11. private Object data;
    12. }

    4.7.创建登录参数的实体类加swagger注解

    1. @Data
    2. @AllArgsConstructor
    3. @NoArgsConstructor
    4. @ApiModel("登录的参数的实体类")
    5. public class VoLogin {
    6. //这里面的参数必须和你前端请求的参数相同
    7. @ApiModelProperty("账号")
    8. private String name;
    9. @ApiModelProperty("密码")
    10. private String password;
    11. }

    4.8.后端登录接口加swagger的注解

    1. @RestController
    2. @RequestMapping("/system")
    3. @Api(tags = "登录的类")
    4. public class LoginController {
    5. @Autowired
    6. private IUserService userService;
    7. @Autowired
    8. private RedisTemplate redisTemplate;
    9. @PostMapping("/user")
    10. @ApiOperation(value = "登录的接口")
    11. /*
    12. * origins: 允许哪些域可以跨域访问我这个接口
    13. allowedHeaders:允许哪些请求头信息跨域
    14. methods: 允许哪些请求方式跨域
    15. * */
    16. // @CrossOrigin //默认不写是*--解决跨域的问题
    17. public CommonResult login(@RequestBody VoLogin voLogin){
    18. QueryWrapper wrapper=new QueryWrapper<>();
    19. wrapper.eq("username",voLogin.getName());
    20. wrapper.eq("password",voLogin.getPassword());
    21. wrapper.eq("is_deleted",0);
    22. User one = userService.getOne(wrapper);
    23. if (one!= null) {
    24. return new CommonResult(2000,"登录成功",null);
    25. }else {
    26. return new CommonResult(5000,"登录失败",null);
    27. }
    28. }
    29. }

    5.登录的bug

    5.1.修改登录接口

    5.1.1.如果在数据库查询到了用户信息,然后将用户信息保存

    1. @RestController
    2. @RequestMapping("/system")
    3. @Api(tags = "登录的类")
    4. public class LoginController {
    5. @Autowired
    6. private IUserService userService;
    7. @Autowired
    8. private RedisTemplate redisTemplate;
    9. @PostMapping("/user")
    10. @ApiOperation(value = "登录的接口")
    11. /*
    12. * origins: 允许哪些域可以跨域访问我这个接口
    13. allowedHeaders:允许哪些请求头信息跨域
    14. methods: 允许哪些请求方式跨域
    15. * */
    16. // @CrossOrigin //默认不写是*--解决跨域的问题
    17. public CommonResult login(@RequestBody VoLogin voLogin){
    18. QueryWrapper wrapper=new QueryWrapper<>();
    19. wrapper.eq("username",voLogin.getName());
    20. wrapper.eq("password",voLogin.getPassword());
    21. wrapper.eq("is_deleted",0);
    22. User one = userService.getOne(wrapper);
    23. if (one!= null) {
    24. //登录成功之后随机生成唯一的字符串
    25. String token = UUID.randomUUID().toString();
    26. // System.out.println(token+"---------");
    27. //把token作为key,user的信息是value
    28. ValueOperations forValue = redisTemplate.opsForValue();
    29. forValue.set(token,one,24,TimeUnit.HOURS);
    30. //把token返回给前端,作为主体
    31. return new CommonResult(2000,"登录成功",token);
    32. }else {
    33. return new CommonResult(5000,"登录失败",null);
    34. }
    35. }

    5.1.2.将保存的信息给前端

    1. methods:{
    2. login(){
    3. this.$refs['ruleForm'].validate((valid) => {
    4. if(valid) {
    5. // url:后端登录接口的路径
    6. this.axios.post("http://localhost:8888/system/user", this.ruleForm).then(result => {
    7. if(result.data.code===2000){
    8. //登录成功,获取token
    9. var token = result.data.data;
    10. // console.log(result.data.data)
    11. //把token保存
    12. sessionStorage.setItem("token",token);
    13. //登录成功之后跳转到主页面--路由跳转
    14. this.$router.push("/home")
    15. }
    16. });
    17. }

    由于每次前端都往后端请求都得要人为添加参数token. 我们可以使用axios得请求拦截器。

    5.1.3.axios得请求拦截器、

    1. //使用axios的请求拦截器,--在请求头上添加token
    2. //interceptors--拦截器 request--请求方法 use--用
    3. axios.interceptors.request.use(config=>{
    4. //获取token
    5. var token = sessionStorage.getItem("token");
    6. //判断toke里面是不是有值
    7. if (token){
    8. //请求头中会携带token
    9. config.headers.token=token;
    10. }
    11. return config;
    12. })

    6.前置路由守卫

    6.1.什么是前置路由守卫

    路由跳转之前, 会触发的一个函数 叫前置路由守卫

    6.2.前置路由守卫的语法

    router.beforeEach((to, from, next) => {})

    to : 到哪里去

    from : 从哪里来

    next : 放行函数 next():放行 , next(false):不放行

    6.3.使用前置路由守卫 --在main.js

    1. router.beforeEach((to, from, next) =>{
    2. var path = to.path;
    3. //判断是不是登录页面
    4. if (path==="/login"){
    5. //放行
    6. return next();
    7. }
    8. //判断其他页面是否登录,登录放行
    9. var token = sessionStorage.getItem("token");
    10. if(token){
    11. return next();
    12. }
    13. //没有登录的话,跳转到登录页面
    14. return next("/login");
    15. } )

    7.整合shiro

    7.1.添加shiro依赖

           
                org.apache.shiro
                shiro-spring-boot-starter
                1.7.0
           

    7.2.shiro得配置类

    这里面注入RedisTemplate的原因,请看跨域那一篇的笔记

    1. package com.guan.demo.system.config;
    2. import com.guan.demo.system.filter.LoginFilter;
    3. import com.guan.demo.system.realm.MyRealm;
    4. import org.apache.shiro.authc.credential.CredentialsMatcher;
    5. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    6. import org.apache.shiro.realm.Realm;
    7. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    8. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    9. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    10. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    11. import org.springframework.beans.factory.annotation.Autowired;
    12. import org.springframework.boot.web.servlet.FilterRegistrationBean;
    13. import org.springframework.context.annotation.Bean;
    14. import org.springframework.context.annotation.Configuration;
    15. import org.springframework.data.redis.core.RedisTemplate;
    16. import org.springframework.web.filter.DelegatingFilterProxy;
    17. import javax.servlet.Filter;
    18. import java.util.HashMap;
    19. import java.util.Map;
    20. /**
    21. * TODO
    22. *
    23. * @author lenovo
    24. * @version 1.0
    25. * @since 2022-08-05 20:05:38
    26. */
    27. @Configuration
    28. public class ShiroConfig {
    29. @Bean
    30. public DefaultWebSecurityManager securityManager(){
    31. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    32. securityManager.setRealm(realm());
    33. return securityManager;
    34. }
    35. @Bean
    36. public Realm realm(){
    37. MyRealm myRealm = new MyRealm();
    38. 设置密码加密器
    39. myRealm.setCredentialsMatcher(credentialsMatcher());
    40. return myRealm;
    41. }
    42. @Bean
    43. public CredentialsMatcher credentialsMatcher(){
    44. //设置密码加密器
    45. HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    46. //加密的次数
    47. hashedCredentialsMatcher.setHashIterations(1024);
    48. //应那种加密方式加密
    49. hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    50. return hashedCredentialsMatcher;
    51. }
    52. @Autowired
    53. private RedisTemplate redisTemplate;
    54. @Bean("shiroFilter")
    55. public ShiroFilterFactoryBean filterFactoryBean(){
    56. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    57. shiroFilterFactoryBean.setSecurityManager(securityManager());
    58. //设置shiro过滤规则
    59. Map map = new HashMap<>();
    60. //那些允许放行
    61. map.put("/system/login","anon");
    62. //拦截所有
    63. map.put("/**","authc");
    64. shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
    65. //设置未登录过滤器
    66. Map filters = new HashMap<>();
    67. filters.put("authc",new LoginFilter(redisTemplate));
    68. shiroFilterFactoryBean.setFilters(filters);
    69. return shiroFilterFactoryBean;
    70. }
    71. @Bean
    72. public FilterRegistrationBean filterProxy(){
    73. FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean<>();
    74. //设置过滤器
    75. filterRegistrationBean.setFilter(new DelegatingFilterProxy());
    76. //那个路径过滤
    77. filterRegistrationBean.setName("shiroFilter");
    78. filterRegistrationBean.addUrlPatterns("/*");
    79. return filterRegistrationBean;
    80. }
    81. }

    7.3.增加一个realm类对象

    1. package com.guan.demo.system.realm;
    2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    3. import com.guan.demo.system.entity.User;
    4. import com.guan.demo.system.service.IUserService;
    5. import com.guan.demo.system.vo.VoLogin;
    6. import org.apache.shiro.authc.AuthenticationException;
    7. import org.apache.shiro.authc.AuthenticationInfo;
    8. import org.apache.shiro.authc.AuthenticationToken;
    9. import org.apache.shiro.authc.SimpleAuthenticationInfo;
    10. import org.apache.shiro.authz.AuthorizationInfo;
    11. import org.apache.shiro.authz.SimpleAuthorizationInfo;
    12. import org.apache.shiro.realm.AuthorizingRealm;
    13. import org.apache.shiro.subject.PrincipalCollection;
    14. import org.apache.shiro.util.ByteSource;
    15. import org.springframework.beans.factory.annotation.Autowired;
    16. import java.util.List;
    17. /**
    18. * TODO
    19. *
    20. * @author lenovo
    21. * @version 1.0
    22. * @since 2022-08-05 20:07:04
    23. */
    24. public class MyRealm extends AuthorizingRealm {
    25. @Autowired
    26. private IUserService userService;
    27. @Override
    28. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    29. return null;
    30. }
    31. @Override
    32. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    33. //根据token拿到账号
    34. String username = (String) token.getPrincipal();
    35. //根据账号查询信息
    36. QueryWrapper wrapper = new QueryWrapper<>();
    37. wrapper.eq("username",username);
    38. wrapper.eq("is_deleted",0);
    39. User user = userService.getOne(wrapper);
    40. //如果user里面查询到了,有值不为空,从数据库中获取密码
    41. if(user!=null){
    42. //从数据库中获取的密码
    43. //第一个参数是唯一标识,第二个参我们获取到user的密码,第三个参数就是获取到当前的名字
    44. ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
    45. SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,this.getName());
    46. return info;
    47. }
    48. return null;
    49. }
    50. }

    7.4.新增一个拦截器

    1. //如果类没有交于spring容器来管理 那么该类中得属性也不能让spring帮你注入
    2. public class LoginFilter extends FormAuthenticationFilter {
    3. private RedisTemplate redisTemplate; //没有自动注入,原因该类没有交于spring管理LoginFilter必须交于spring容器来管理。
    4. //构造方法
    5. public LoginFilter(RedisTemplate redisTemplate) {
    6. this.redisTemplate = redisTemplate;
    7. }
    8. //当登录成功后执行得方法,如果该方法返回false,则执行onAccessDenied方法,true则不会执行onAccessDenied方法
    9. @Override
    10. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
    11. System.out.println(redisTemplate);
    12. HttpServletRequest req = (HttpServletRequest) request;
    13. //1.请求方式是否为OPTIONS
    14. String method = req.getMethod();
    15. //如果请求方式不为空,并且请求方式是OPTIONS,则不执行onAccessDenied方法
    16. if(method!=null && method.equals("OPTIONS")){
    17. return true;
    18. }
    19. //2.判断请求头是否有token值
    20. String token = req.getHeader("token");
    21. if(token!=null && redisTemplate.hasKey(token)){
    22. return true;
    23. }
    24. return false;
    25. }
    26. //当没有登录时会经过该方法。如果想让他返回json数据那么必须重写方法
    27. @Override
    28. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    29. response.setContentType("application/json;charset=utf-8");
    30. PrintWriter writer = response.getWriter();
    31. CommonResult commonResult = new CommonResult(4001, "未登录", null);
    32. ObjectMapper objectMapper=new ObjectMapper();
    33. String json = objectMapper.writeValueAsString(commonResult);
    34. writer.print(json); //响应给客户json数据
    35. writer.flush();
    36. writer.close();
    37. return false;
    38. }
    39. }

    7.5.修改controller代码

    1. //登录
    2. @PostMapping("/login")
    3. @ApiOperation(value = "登录的接口")
    4. /*
    5. * origins: 允许哪些域可以跨域访问我这个接口
    6. allowedHeaders:允许哪些请求头信息跨域
    7. methods: 允许哪些请求方式跨域
    8. * */
    9. // @CrossOrigin //默认不写是*--解决跨域的问题
    10. public CommonResult login(@RequestBody VoLogin voLogin){
    11. try {
    12. //获取subject对象
    13. Subject subject = SecurityUtils.getSubject();
    14. UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(voLogin.getName(),voLogin.getPassword());
    15. //登录
    16. subject.login(usernamePasswordToken);
    17. //获取主体
    18. Object one = subject.getPrincipal();
    19. //登录成功之后随机生成唯一的字符串
    20. String token = UUID.randomUUID().toString();
    21. // System.out.println(token+"---------");
    22. //把token作为key,user的信息是value
    23. ValueOperations forValue = redisTemplate.opsForValue();
    24. forValue.set(token,one,24,TimeUnit.HOURS);
    25. //把token返回给前端,作为主体
    26. return new CommonResult(2000,"登录成功",token);
    27. }catch (Exception e){
    28. return new CommonResult(5000,"登录失败",null);
    29. }
    30. }

    8.主页得布局

    8.1.前端

    1. <template>
    2. <el-container>
    3. <el-header>
    4. <span id="logo" style="display: inline-block;width: 50%;height: 100%;float: left" >
    5. <a href="https://www.bilibili.com/video/BV14g41197PY/"><img src="../assets/logo.png" height="100%" width="180px">a>
    6. span>
    7. <span id="avatar" style="float: right">
    8. <el-dropdown @command="handleCommand">
    9. <span class="el-dropdown-link" style="margin-top: 10px; display: inline-block;" >
    10. <el-avatar >el-avatar>
    11. span>
    12. <el-dropdown-menu slot="dropdown" style="margin-top: -9px">
    13. <el-dropdown-item command="personal">个人信息el-dropdown-item>
    14. <el-dropdown-item command="loginOut">退出登录el-dropdown-item>
    15. el-dropdown-menu>
    16. el-dropdown>
    17. span>
    18. el-header>
    19. <el-container height="600px">
    20. el-container>
    21. template>

     样式

    1. <style>
    2. body{
    3. margin: 0px;
    4. padding: 0px;
    5. }
    6. .el-menu{
    7. border:0px;
    8. background-color:#C0C4CC;
    9. }
    10. .el-header, .el-footer {
    11. background-color: #818181;
    12. color: #333;
    13. height: 60px;
    14. line-height: 60px;
    15. }
    16. .el-aside {
    17. background-color: #C0C4CC;
    18. color: #333;
    19. height: 600px;
    20. line-height: 600px;
    21. /*overflow: hidden;*/
    22. }
    23. .el-aside::-webkit-scrollbar {
    24. display: none;
    25. }
    26. .el-main {
    27. background-color: #E9EEF3;
    28. color: #333;
    29. text-align: center;
    30. height: 600px;
    31. line-height: 600px;
    32. overflow: hidden;
    33. }
    34. body > .el-container {
    35. margin-bottom: 40px;
    36. }
    37. .el-container:nth-child(5) .el-aside,
    38. .el-container:nth-child(6) .el-aside {
    39. line-height: 260px;
    40. }
    41. .el-container:nth-child(7) .el-aside {
    42. line-height: 320px;
    43. }
    44. .el-dropdown {
    45. vertical-align: top;
    46. }
    47. .el-dropdown + .el-dropdown {
    48. margin-left: 15px;
    49. }
    50. .el-icon-arrow-down {
    51. font-size: 12px;
    52. }
    53. /*设置标签页第一个不可删除*/
    54. .el-tabs__nav .el-tabs__item:nth-child(1) span{
    55. display: none;
    56. }
    57. style>

    9.退出登录

    9.1.前端

    1. //退出
    2. handleCommand(command){
    3. if (command==='loginOut'){
    4. this.axios.post("/system/loginOut").then(result=>{
    5. if (result.data.code===2000){
    6. //删除缓存的信息
    7. sessionStorage.getItem("token");
    8. //跳转到登录页面
    9. this.$router.push("/login")
    10. }
    11. })
    12. }
    13. }

    9.2.后端

    1. @Autowired
    2. private RedisTemplate redisTemplate;
    3. //退出
    4. @PostMapping("/loginOut")
    5. public CommonResult loginOut(HttpServletRequest request){
    6. String token = request.getHeader("token");
    7. redisTemplate.delete(token);
    8. return new CommonResult(2000,"退出成功",null);
    9. }

    10.查询左侧菜单

    10.1.前端

    1. <el-container height="600px">
    2. <el-aside width="200px">
    3. <el-menu
    4. default-active="2"
    5. class="el-menu-vertical-demo"
    6. background-color="#C0C4CC"
    7. text-color="#000"
    8. active-text-color="#ffd04b">
    9. <el-submenu :index="menu.id+''" v-for="menu in leftMenus">
    10. <template slot="title">
    11. <i class="el-icon-location">i>
    12. <span>{{menu.name}}span>
    13. template>
    14. <el-menu-item :index="second.id+''" v-for="second in menu.children">
    15. <i :class="el-icon-menu">i>
    16. <span slot="title">
    17. <a style="color: white; text-decoration: none ">{{second.name}}a>span>
    18. el-menu-item>
    19. el-submenu>
    20. el-menu>
    21. el-aside>
    22. <el-main>el-main>
    23. el-container>

     10.2.请求路径

    1. data(){
    2. return{
    3. leftMenus:[],
    4. }
    5. },
    6. created() {
    7. this.initLeftMenu();
    8. },
    9. methods:{
    10. initLeftMenu(){
    11. this.axios.post("/system/permission/leftMenu").then(result=>{
    12. if(result.data.code===2000){
    13. this.leftMenus=result.data.data;
    14. }
    15. })
    16. },

    10.3.controller层

    1. @RestController
    2. @RequestMapping("/system/permission")
    3. public class PermissionController {
    4. @Autowired
    5. private IPermissionService permissionService;
    6. @PostMapping("leftMenu")
    7. public CommonResult leftMenu(HttpServletRequest request){
    8. //获取登录者的信息
    9. String token = request.getHeader("token");
    10. return permissionService.findPermissionByUserId(token);
    11. }
    12. }

    10.4.service层

    1. public interface IPermissionService extends IService {
    2. CommonResult findPermissionByUserId(String token);
    3. }

     10.5.mapper层

    1. public interface PermissionMapper extends BaseMapper {
    2. List selectByUserId(String id);
    3. }

    10.6.seriveimpl业务代码

    1. @Autowired
    2. private PermissionMapper permissionMapper;
    3. @Autowired
    4. private RedisTemplate redisTemplate;
    5. @Override
    6. public CommonResult findPermissionByUserId(String token) {
    7. //根据token获取用户信息
    8. ValueOperations forValue = redisTemplate.opsForValue();
    9. User o = (User) forValue.get(token);
    10. String id = o.getId();
    11. //根据用户id查询该用户具有得权限。
    12. List permissionList = permissionMapper.selectByUserId(id);
    13. //设置层级关系
    14. List firstMenus = new ArrayList<>();
    15. for (Permission first : permissionList) {
    16. //找一级菜单
    17. if (first.getPid().equals("1")) {
    18. firstMenus.add(first);
    19. }
    20. }
    21. //为一级菜单设置二级菜单
    22. for (Permission first : firstMenus) {
    23. //根据一级菜单id 查询 该菜单得二级菜单。如果出现不确定有几级菜单 那么我们可以使用方法得递归调用
    24. first.setChildren(findChildren(permissionList, first.getId()));
    25. }
    26. return new CommonResult(2000,"查询成功",firstMenus);
    27. }
    28. //方法递归
    29. private List findChildren(List permissionList, String id) {
    30. List children = new ArrayList<>();
    31. for (Permission p : permissionList) {
    32. if (p.getPid().equals(id)) {
    33. children.add(p);
    34. }
    35. }
    36. for (Permission child : children) {
    37. child.setChildren(findChildren(permissionList, child.getId()));
    38. }
    39. return children;
    40. }
    41. }

    10.7.连表

    1. <select id="selectByUserId" resultType="com.guan.demo.system.entity.Permission">
    2. select distinct p.* from acl_user_role ur join acl_role_permission rp on ur.role_id=rp.role_id join acl_permission
    3. p on rp.permission_id=p.id where ur.user_id=#{userid} and type=1
    4. select>

  • 相关阅读:
    Request的总结
    Linux安装Phantomjs
    阿里云服务器公网带宽收费价格表_1M到100M报价
    【python】基础语法
    中期科技:智慧公厕打造智能化城市设施,提升公共厕所管理与服务体验
    狗都会用的余弦退火(CosineAnnealingLR)学习率调节算法讲解
    【云原生 | Kubernetes 系列】RBAC 鉴权
    用全栈智能,联想如何“零故障”支持亚运会?
    基于Java后端与Typescript前端的代码自动生成 - malcolmcrum
    堆排序 — — 堆结构及问题【十大经典排序算法】
  • 原文地址:https://blog.csdn.net/ne_123456/article/details/126235787