SpringBoot整合Spring Security实现用户角色验证以及权限控制


一。Spring Security介绍

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它 是Spring生态系统中的一员,因此它伴随着整个Spring生态系统不断修正、升级,在spring boot项目中加入spring security更是十分简单,使用Spring Security 减少了为企业系统安全控制编写大量重复代码的工作。

二。工程搭建

1.工程结构图:

在这里插入图片描述

2.导入依赖

pom.xml内容如下所示:

<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima.security</groupId>
    <artifactId>security-springboot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 以下是>spring boot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 以下是>spring security依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>


        <!-- 以下是jsp依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--jsp页面使用jstl标签 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--用于编译jsp -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>security-springboot</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>

                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <configuration>
                        <encoding>utf-8</encoding>
                        <useDefaultDelimiters>true</useDefaultDelimiters>
                        <resources>
                            <resource>
                                <directory>src/main/resources</directory>
                                <filtering>true</filtering>
                                <includes>
                                    <include>**/*</include>
                                </includes>
                            </resource>
                            <resource>
                                <directory>src/main/java</directory>
                                <includes>
                                    <include>**/*.xml</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

其中,整合spring security最主要的依赖如下所示:

<!-- 以下是>spring security依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

3.编写security配置类

新建WebConfig配置类,实现WebMvcConfigurer接口,配置项目启动默认跳转页面,这里是配置到login.jsp页面:

package com.security.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration//就相当于springmvc.xml文件
public class WebConfig implements WebMvcConfigurer {

    //默认Url根路径跳转到/login,此url为spring security提供
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login-view");
        registry.addViewController("/login-view").setViewName("login");

    }

}

新建WebSecurityConfig配置类,实现WebSecurityConfigurerAdapter接口,配置安全拦截机制:

package com.security.springboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    //密码编码器(用户密码存入数据为BCryptPasswordEncoder加密的方式存入)
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/r/**").authenticated()//所有/r/**的请求必须认证通过
                .anyRequest().permitAll()//除了/r/**,其它的请求可以访问
                .and()
                .formLogin()//允许表单登录
                .loginPage("/login-view")//登录页面
                .loginProcessingUrl("/login")
                .successForwardUrl("/login-success")//自定义登录成功的页面地址
        .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login-view?logout");


    }
}

4.编写UserDetailsService验证类

什么是UserDetailsService ?

现在咱们现在知道DaoAuthenticationProvider处理了web表单的认证逻辑,认证成功后既得到一个 Authentication(UsernamePasswordAuthenticationToken实现),里面包含了身份信息(Principal)。这个身份 信息就是一个 Object ,大多数情况下它可以被强转为UserDetails对象。

DaoAuthenticationProvider中包含了一个UserDetailsService实例,它负责根据用户名提取用户信息 UserDetails(包含密码),而后DaoAuthenticationProvider会去对比UserDetailsService提取的用户密码与用户提交 的密码是否匹配作为认证成功的关键依据,因此可以通过将自定义的 UserDetailsService 公开为spring bean来定 义自定义身份验证。

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

很多人把DaoAuthenticationProvider和UserDetailsService的职责搞混淆,其实UserDetailsService只负责从特定 的地方(通常是数据库)加载用户信息,仅此而已。而DaoAuthenticationProvider的职责更大,它完成完整的认 证流程,同时会把UserDetails填充至Authentication。

上面一直提到UserDetails是用户信息,咱们看一下它的真面目:

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

它和Authentication接口很类似,比如它们都拥有username,authorities。Authentication的getCredentials()与 UserDetails中的getPassword()需要被区分对待,前者是用户提交的密码凭证,后者是用户实际存储的密码,认证 其实就是对这两者的比对。Authentication中的getAuthorities()实际是由UserDetails的getAuthorities()传递而形 成的。还记得Authentication接口中的getDetails()方法吗?其中的UserDetails用户详细信息便是经过了 AuthenticationProvider认证之后被填充的。

通过实现UserDetailsService和UserDetails,我们可以完成对用户信息获取方式以及用户信息字段的扩展。 Spring Security提供的InMemoryUserDetailsManager(内存认证),JdbcUserDetailsManager(jdbc认证)就是 UserDetailsService的实现类,主要区别无非就是从内存还是从数据库加载用户。

编写SpringDataUserDetailsService类,实现UserDetailsService接口,从数据库查询用户信息。(认证逻辑会首先通过这个验证类来验证用户是否存在

package com.security.springboot.service;

import com.security.springboot.dao.UserDao;
import com.security.springboot.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SpringDataUserDetailsService implements UserDetailsService {

    @Autowired
    UserDao userDao;

    //根据 账号查询用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //将来连接数据库根据账号查询用户信息
        User user = userDao.getUserByUsername(username);
        if(user == null){
            //如果用户查不到,返回null,由provider来抛出异常
            return null;
        }
        //根据用户的id查询用户的权限
        List<String> permissions = userDao.findPermissionsByUserId(user.getId());
        //将permissions转成数组
        String[] permissionArray = new String[permissions.size()];
        permissions.toArray(permissionArray);
        UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(user.getUsername()).password(user.getPassword()).authorities(permissionArray).build();
        return userDetails;
    }
}

5.Dao层

编写UserDao类,从数据库获取信息:

package com.security.springboot.dao;

import com.security.springboot.model.Permission;
import com.security.springboot.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
public class UserDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    //根据账号查询用户信息
    public User getUserByUsername(String username){
        String sql = "select id,username,password,fullname,mobile from t_user where username = ?";
        //连接数据库查询用户
        List<User> list = jdbcTemplate.query(sql, new Object[]{username}, new BeanPropertyRowMapper<>(User.class));
        if(list !=null && list.size()==1){
            return list.get(0);
        }
        return null;
    }

    //根据用户id查询用户权限
    public List<String> findPermissionsByUserId(String userId){
        String sql = "SELECT * FROM t_permission WHERE id IN(\n" +
                "\n" +
                "SELECT permission_id FROM t_role_permission WHERE role_id IN(\n" +
                "  SELECT role_id FROM t_user_role WHERE user_id = ? \n" +
                ")\n" +
                ")\n";

        List<Permission> list = jdbcTemplate.query(sql, new Object[]{userId}, new BeanPropertyRowMapper<>(Permission.class));
        List<String> permissions = new ArrayList<>();
        list.forEach(c -> permissions.add(c.getCode()));
        return permissions;
    }
}

6.model层

User:

package com.security.springboot.model;

import lombok.Data;

/**
 * 用户实体
 */
@Data
public class User {
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}

Permission:

package com.security.springboot.model;

import lombok.Data;

/**
 * 用户关联权限实体
 */
@Data
public class Permission {

    private String id;
    private String code;         //用户权限
    private String description;  //权限描述
    private String url;          //资源url
}

7.控制器层

LoginController:

package com.security.springboot.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {
    /**
     * 登录成功执行接口
     * @return
     */
    @RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})
    public String loginSuccess(){
        //提示具体用户名称登录成功
        return getUsername()+" 登录成功";
    }

    /**
     * 测试资源1
     * @return
     */
    @GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})
    @PreAuthorize("hasAuthority('p1')")//拥有p1权限才可以访问
    public String r1(){
        return getUsername()+" 访问资源1";
    }

    /**
     * 测试资源2
     * @return
     */
    @GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})
    @PreAuthorize("hasAuthority('p2')")//拥有p2权限才可以访问
    public String r2(){
        return getUsername()+" 访问资源2";
    }

    /**
     * 无需认证测试接口
     * @return
     */
    @GetMapping(value = "test",produces = {"text/plain;charset=UTF-8"})
    public String test(){
        return "无需认证测试接口 ";
    }

    //获取当前用户信息
    private String getUsername(){
        String username = null;
        //当前认证通过的用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //用户身份
        Object principal = authentication.getPrincipal();
        if(principal == null){
            username = "匿名";
        }
        if(principal instanceof org.springframework.security.core.userdetails.UserDetails){
            UserDetails userDetails = (UserDetails) principal;
            username = userDetails.getUsername();
        }else{
            username = principal.toString();
        }
        return username;
    }


}

8.工具类

因为SpringSecurity框架中,数据库存放的用户密码是以加密的方式来进行存储的,在本项目我们采用BCryptPasswordEncoder加密。

首先我们需要在之前的WebSecurityConfig配置类中声明:
在这里插入图片描述
BCryptPasswordEncoder加密工具类BCPEUtils代码如下所示:

package com.security.springboot.util;
 
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 
/**
 * SpringSecurity中的BCryptPasswordEncoder加密
 */
public class BCPEUtils {
 
    private static BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    /**
     *  将原生密码进行加密
     * @return 加密后的字符串密码
     */
    public static String encode(String rawPWD){
        String hashedPassword = passwordEncoder.encode(rawPWD);
        return hashedPassword;
    }
 
    /**
     * 比较原生密码与密文是否一致
     * @param rawPWD 原生密码
     * @param encodePWD 密文
     * @return true/false
     */
    public static boolean matches(String rawPWD,String encodePWD){
        boolean result = passwordEncoder.matches(rawPWD, encodePWD);
        return result;
    }


    public static void main(String[] args) {
        String password="123456";
        String rePassword=BCPEUtils.encode(password);
        System.out.println(rePassword);
        System.out.println("----------------------");
        System.out.println(BCPEUtils.matches(password,rePassword));
    }
}

9.配置文件

application.yml配置内容如下:

server:
  port: 8080
  servlet:
    context-path: /security-springboot  #访问前缀
spring:
  application:
    name: security-springboot
  mvc:
    view:   #视图解析器
      prefix: /WEB-INF/view/
      suffix: .jsp
  datasource:  #连接数据库信息
    url: jdbc:mysql://localhost:3306/user_db
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver




10.jsp示例登录页面

login.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>
<form action="login" method="post">
    用户名:<input type="text" name="username"><br>&nbsp;&nbsp;&nbsp;码:
    <input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

11.启动类

SecuritySpringBootApp:

package com.security.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SecuritySpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(SecuritySpringBootApp.class,args);
    }
}

三。数据库结构

由于本项目中的验证是从数据库中读取用户数据,所以我们需要创建一个名为user_db的数据库,并创建五张数据表

t_user(用户表)

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` bigint(20) NOT NULL COMMENT '用户id',
  `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `fullname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户姓名',
  `mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `t_user` VALUES (1, 'zhangsan', '$2a$10$3MYHLGvYkYgCKRAXNeEDTe1g7AznV/Ni7pmXP2zD0V0YS/HosBamu', '张三', '12345674891');

创建完成后如下所示:
在这里插入图片描述

t_role(角色表)

DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role`  (
  `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `create_time` datetime NULL DEFAULT NULL,
  `update_time` datetime NULL DEFAULT NULL,
  `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `unique_role_name`(`role_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `t_role` VALUES ('1', '管理员', NULL, NULL, NULL, '');

创建完成后如下所示:
在这里插入图片描述

t_permission(权限表)

DROP TABLE IF EXISTS `t_permission`;
CREATE TABLE `t_permission`  (
  `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限标识符',
  `description` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
  `url` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `t_permission` VALUES ('1', 'p1', '测试资源 1', '/r/r1');
INSERT INTO `t_permission` VALUES ('2', 'p3', '测试资源2', '/r/r2');

创建完成后如下所示:
在这里插入图片描述

t_user_role(用户角色表)

DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role`  (
  `user_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `create_time` datetime NULL DEFAULT NULL,
  `creator` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`, `role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `t_user_role` VALUES ('1', '1', NULL, NULL);

创建完成后如下所示:
在这里插入图片描述

t_permission(角色权限表)

DROP TABLE IF EXISTS `t_role_permission`;
CREATE TABLE `t_role_permission`  (
  `role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `permission_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`role_id`, `permission_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `t_role_permission` VALUES ('1', '1');
INSERT INTO `t_role_permission` VALUES ('1', '2');

创建完成后如下所示:
在这里插入图片描述

四。测试

1.用户登录验证

1.Debug启动项目,在SpringDataUserDetailsService上面打断点:
在这里插入图片描述
2.在浏览器访问 http://localhost:8080/security-springboot,自动跳到登录页面:
在这里插入图片描述
3.输入用户名以及用户密码,点击登录按钮:
在这里插入图片描述
4.跳到后台SpringDataUserDetailsService用户验证逻辑中,拿到用户信息:
在这里插入图片描述
5.用户验证成功后:
在这里插入图片描述

2.用户权限验证

1.访问http://localhost:8080/security-springboot/r/r1,由于张三角色含有p1,p3权限,所以可以成功进行访问:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.访问http://localhost:8080/security-springboot/r/r2,访问失败:
在这里插入图片描述
在这里插入图片描述
3.无需权限认证访问接口,访问成功:
在这里插入图片描述在这里插入图片描述

五。项目地址

该项目已经上传至百度网盘,有需要的小伙伴可自行下载:

链接:https://pan.baidu.com/s/1g6EqQMvje653zTjySy-sCA
提取码:lig3

  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
《Vue和SpringBoot打造假日旅社管理系统》课程,将讲解如何使用Vue和SpringBoot开发这个项目,手把手演示开发流程!附赠源码、文档、数据库脚本等全部资料,提供售后答疑。 课程简介本课程讲解的是《基于 Vue 和 SpringBoot 的假日旅社管理系统》,该系统支持民宿档案、民宿新闻、民宿预定、民宿评论这四大核心业务,适用于乡村民宿企业的民宿预定业务。系统给每个民宿档案提供一个唯一标识,对民宿预定、评论等各个环节进行快速批量的数据采集,确保游客及时掌握景区民宿的真实数据,方便游客进行民宿预定。另外系统还包括员工管理、组织机构管理、文件管理、权限管理功能,给旅社企业提供更个性化的民宿管理模式。假日旅社管理系统采用了基于角色的访问控制角色和菜单关联,一个角色可以配置多个菜单权限;然后再将用户角色关联,一位用户可以赋予多个角色。这样用户就可以根据角色拿到该有的菜单权限,更方便旅社企业的管理人员进行权限管控。   软件技术选型前端Vue:Vue 是构建前端界面的核心框架,本系统采用 2.6.14 版本。View UI:基于 Vue.js2.0 的组件库,本系统采用 4.7.0 版本。后端Spring Boot:构建系统核心逻辑的后端框架,本系统采用 2.7.0 版本。MyBatis / MyBatis Plus:后端连接数据库的框架,本系统采用 3.5.2 版本。数据库MySQL:本项目的主数据库,本系统采用 8.0.29 版本。Redis:本系统采用基于 Windows 版本的 Redis,用于图形验证码和用户菜单权限的临时存储,采用了 5.0.14 版本。开发环境VsCode:项目前端的开发工具,使用版本为 1.68.0。IntelliJ IDEA :项目后端的开发工具,使用版本为 2021.3.2。Jdk:Java 的开发环境,使用版本为 17.0.3.1。Maven:后端项目的打包工具,使用版本为 3.6.2。NodeJs:前端项目的开发环境,使用版本为 16.13.0。 软件架构分析基于 Vue 和 SpringBoot 的假日旅社管理系统包括了系统基础模块、民宿档案模块、民宿新闻模块、民宿预定模块、民宿评论模块这五大功能模块,其架构如下图所示。  接下来,分别对五大模块进行详细介绍。系统基础模块系统基础模块,是用于支撑假日旅社管理系统的正常运行,这个模块包括了登陆注册模块、员工部门管理、菜单权限管理等。假日旅社管理系统支持用户使用账号、密码和图形验证码登陆,操作界面如下图所示。  假日旅社管理系统支持用户使用手机号、姓名、密码和图形验证码注册,操作界面如下图所示。 用户成功进入系统后,可进入到基于 Vue 和 SpringBoot 的假日旅社管理系统的首页,首页展示了当前登陆的地址、现在的时间和用户配置的常用模块,如下图所示。 接着用户点击左侧的用户管理,即可进入用户管理模块,用户管理模块的首页如下图所示。 用户可以在这个模块对系统登陆用户的档案进行维护,包括添加新用户、删除用户、编辑用户、根据姓名/部门查询用户用户可以进入部门管理模块,管理旅社的部门数据,如下图所示。 同理用户可以进入到菜单管理模块,对系统的菜单进行管理,菜单管理模块的操作界面如下图所示。 民宿档案模块第二个模块是民宿档案模块,民宿档案就是用来管理民宿的数据,民宿档案包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿档案模块的主界面。用户可以点击顶部的“新增”按钮,进入民宿档案添加界面,添加民宿档案数据,如下图所示。 其中房间类型为下拉框单项选择,如下图所示。还有早餐情况也是下拉单选,如下图所示。 用户可以对现有的民宿档案数据进行编辑更新,只需点击每一行民宿档案数据的“编辑”按钮,即可进入民宿档案数据的编辑界面,如下图所示。 用户也可以对不需要的民宿数据进行删除操作,用户点击删除时,系统会弹出二次确认弹框,如下图所示。  民宿新闻模块第三个模块是民宿新闻模块,民宿新闻就是用来管理民宿的新闻资讯,包含的功能如下所示。 民宿新闻包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿新闻模块的主界面,其中的图片仅供测试样例使用。用户可以点击顶部的“新增”按钮,进入民宿新闻添加界面,添加民宿新闻数据,如下图所示。 新闻描述字段采用了 ueditor 富文本编辑器,这是由百度 web 前端研发部开发的所见即所得的开源富文本编辑器,具有轻量、可定制、用户体验优秀等特点,基于 MIT 开源协议,所有源代码可自由修改和使用。 用户可以对现有的民宿新闻数据进行编辑更新,只需点击每一行民宿新闻数据的“编辑”按钮,即可进入民宿新闻数据的编辑界面,如下图所示。 民宿预定模块第四个模块是民宿预定模块,旅客可以在民宿预定模块中预定民宿,达到旅客的住宿目的,民宿预定模块包含的功能如下所示。民宿预定包括了预定民宿 ID、预定民宿名称、预定日期、下单时间、下单人 ID、下单人姓名、价格、是否付款、下单备注等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个预约按钮,如下图所示。 如用户点击 1 幢 102 民宿的预约按钮后,会弹出预约确认框,需要输入预约的日期,日期表单默认选择今日,如下图所示。 旅客需要点击“确认预约”按钮,完成预约操作,系统给与“预约成功”提示,如下图所示。 预约成功后,旅客可以从民宿预定模块中进行查询,如下图所示。 最后旅客进行付款操作,点击每一行右侧的付款按钮,如下图所示。支付完成后,系统将预定单的支付状态改为付款,预定流程结束,如下图所示。 民宿评论模块 第五个模块是民宿预定模块,旅客可以在民宿预定结束后评论民宿,以帮助更多的人了解民宿,民宿评论模块包含的功能如下所示。 民宿评论包括了民宿名称、民宿 ID、评论时间、评论内容、评论人 ID、评论人姓名等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个评论按钮,如下图所示。 旅客点击评论后,系统给与弹框反馈,如下图所示。  用户输入评论内容后,点击确认评论按钮,即可完成评论操作,如下图所示。  旅客评论后,即可在民宿评论模块中查看此评论数据,如下图所示。 也可以在民宿模块中,双击民宿数据查看评论信息,如下图所示。 项目总结本软件是基于 Vue 和 SpringBoot 的假日旅社管理系统,包含了民宿档案、民宿新闻、民宿预定、民宿评论这四个功能模块。 开发本系统的目的,就是为了帮助旅游景点的民宿企业提高民宿管理效率,降低人力成本,让旅游景点的民宿企业获得更多的经济效益。
课程简介:历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:
1. 引入依赖 在pom.xml文件中引入Spring Security依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 添加配置类 在项目中添加一个配置类SecurityConfig,继承自WebSecurityConfigurerAdapter。 ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/login", "/register").permitAll() // 登录注册页面不需要验证 .anyRequest().authenticated() // 其他页面需要验证 .and() .formLogin() .loginPage("/login") // 登录页面 .defaultSuccessUrl("/index") // 登录成功后的默认跳转页面 .and() .logout() .logoutUrl("/logout") // 退出登录的URL .logoutSuccessUrl("/login") // 退出登录后跳转到的页面 .invalidateHttpSession(true) .deleteCookies("JSESSIONID"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() // 在内存中存储用户信息 .withUser("admin").password("{noop}admin").roles("ADMIN") .and() .withUser("user").password("{noop}user").roles("USER"); } } ``` 3. 实现登录与注册功能 创建登录页面login.html和注册页面register.html,使用Thymeleaf模板引擎渲染页面。 在Controller中添加登录和注册的请求处理方法。 ``` @Controller public class UserController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") public String loginSuccess() { return "redirect:/index"; } @GetMapping("/register") public String register() { return "register"; } @PostMapping("/register") public String registerSuccess() { return "redirect:/login"; } } ``` 4. 实现用户鉴权功能 在SecurityConfig中重写configure(AuthenticationManagerBuilder auth)方法,实现用户信息的认证。 这里使用inMemoryAuthentication()方法在内存中存储用户信息,实际应用中可以使用数据库存储。 ``` @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() // 在内存中存储用户信息 .withUser("admin").password("{noop}admin").roles("ADMIN") .and() .withUser("user").password("{noop}user").roles("USER"); } ``` 在Controller中添加需要鉴权的请求处理方法,并在方法上添加@PreAuthorize注解指定需要的权限。 ``` @Controller public class UserController { @GetMapping("/admin") @PreAuthorize("hasRole('ADMIN')") public String admin() { return "admin"; } @GetMapping("/user") @PreAuthorize("hasRole('USER')") public String user() { return "user"; } } ``` 5. 配置登录认证 在SecurityConfig中重写configure(HttpSecurity http)方法,配置登录认证信息。 ``` @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/login", "/register").permitAll() // 登录注册页面不需要验证 .anyRequest().authenticated() // 其他页面需要验证 .and() .formLogin() .loginPage("/login") // 登录页面 .defaultSuccessUrl("/index") // 登录成功后的默认跳转页面 .and() .logout() .logoutUrl("/logout") // 退出登录的URL .logoutSuccessUrl("/login") // 退出登录后跳转到的页面 .invalidateHttpSession(true) .deleteCookies("JSESSIONID"); } ``` 6. 测试 启动应用,在浏览器中访问http://localhost:8080/login,输入用户名和密码进行登录,登录成功后跳转到首页。 访问http://localhost:8080/admin和http://localhost:8080/user,根据用户角色的不同,页面会有不同的显示。如果访问没有权限的页面,会自动跳转到登录页面。在登录状态下访问/logout可以退出登录。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Keson Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值