• 一、项目框架
  • 1. 项目结构
  • 2. 选择安装依赖
  • 二、数据库
  • 三、代码实现
  • 实现思路
  • 1. 配置文件
  • 2. 编写测试页面
  • login.jsp
  • register.jsp
  • menu.jsp
  • 3. 配置视图控制器
  • 4. 进行Spring Security配置。
  • 5. 编写dao层和mapper文件
  • 6. 编写service层
  • 7. 编写controller层
  • 附:实体类与帮助类
  • 实体类
  • 帮助类

Spring Security 是一个功能强大且高度可自定义的身份验证和访问控制框架,它侧重于为 Java 应用程序提供身份验证和授权。
官网传送门:Spring Security官网

本篇文章目的在于快速使用Spring Boot与Spring Security搭建一个项目,实现简单的用户注册登录。

此项目所用知识点:

  1. Spring Boot
  2. Spring Security
  3. MySQL
  4. Mybatis
  5. JSP

一、项目框架

1. 项目结构

spring boot jedis用户名 springboot用户登录注册_maven

2. 选择安装依赖

使用Spring Boot进行项目创建。
依赖勾选

  1. Spring Boot DevTools
  2. Spring Web
  3. Spring Security
  4. Mybatis Framework
  5. MySQL Driver

以此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>org.example</groupId>
    <artifactId>springboot-security</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- 引入springboot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.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>
        <!-- jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <!-- tomcat -->
        <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>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 配置tomcat -->
    <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>

二、数据库

共5张表

  1. t_user 用户表
  2. t_role 角色表
  3. r_user_role 用户-角色
  4. r_permission 权限表
  5. r_role_permission 角色-权限
/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50610
 Source Host           : localhost:3306
 Source Schema         : user_db

 Target Server Type    : MySQL
 Target Server Version : 50610
 File Encoding         : 65001

 Date: 21/07/2020 21:29:29
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for 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;

-- ----------------------------
-- Records of t_permission
-- ----------------------------
INSERT INTO `t_permission` VALUES ('1', 'p1', '测试资源1', '/resource/r1');
INSERT INTO `t_permission` VALUES ('2', 'p2', '测试资源2', '/resource/r2');
INSERT INTO `t_permission` VALUES ('3', 'p3', '测试资源3', '/resource/r3');

-- ----------------------------
-- Table structure for 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(0) NULL DEFAULT NULL,
  `update_time` datetime(0) 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;

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

-- ----------------------------
-- Table structure for t_role_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;

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

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT 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 NULL DEFAULT NULL COMMENT '用户姓名',
  `mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, 'zhangsan', '$2a$10$37vdSYJUVguwXpLDnZfEt.UDC0y6Yk2RCzFuJKfOrWCiTnUFlmj3K', NULL, NULL);

-- ----------------------------
-- Table structure for 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(0) 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;

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

SET FOREIGN_KEY_CHECKS = 1;

三、代码实现

实现思路

  1. 配置Spring Boot环境。将服务器配置、数据源、MyBatis映射文件、启动文件完成配置。
  2. 完成基本的jsp页面。用于测试用户注册、登录功能。
  3. 配置视图控制器。将项目的根路径重定向到login-view,再将login-view转发到真实的login.jsp页面。
  4. 进行Spring Security配置。主要配置密码编码器和安全拦截器
  5. 编写dao层和mapper文件。用于连接数据库。
  6. 编写service层。一方面是实现用户的注册和登录,另一方面是实现spring-security核心接口,其负载着用户特定数据,它被用来在整个框架作为一个用户DAO。
  7. 编写controller层。用于页面访问,在controller接口中可以设置接口的访问权限,让Spring Security进行安全验证。

1. 配置文件

application.properties

# web
server.port=8080
server.servlet.context-path=/
spring.application.name=security-springboot
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
# DataSource
spring.datasource.url=jdbc:mysql://localhost:3306/user_db
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# mybatis
mybatis.mapper-locations=classpath:mapper/*.xml

SpringBootApp.java

package com.aaa;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * springboot启动程序
 * @author 淮南King
 */
@SpringBootApplication
@MapperScan("com.aaa.dao")
public class SpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApp.class,args);
    }
}

2. 编写测试页面

spring boot jedis用户名 springboot用户登录注册_security_02

login.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>

<h1>登录</h1>
<form action="/login" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
<hr>
<p><a href="/register">注册</a></p>
</body>
</html>

register.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
    <title>用户注册</title>
</head>
<body>
<h1>注册</h1>
<form action="/user/register" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="注册">
</form>
<hr>
<p><a href="/">登录</a></p>
</body>
</html>

menu.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
    <title>菜单页</title>
</head>
<body>
<h1>菜单页</h1>
欢迎${username}登录
<hr>
<h3><a href="/resource/r1" target="_blank">资源一</a></h3>
<h3><a href="/resource/r2" target="_blank">资源二</a></h3>
<h3><a href="/resource/r3" target="_blank">资源三</a></h3>
</body>
</html>

3. 配置视图控制器

WebConfig.java

package com.aaa.config;

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

/**
 * springmvc配置
 * @author 淮南King
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     * 用此方法来添加视图控制器。
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //将根路径重定向到/login-view
        registry.addViewController("/").setViewName("redirect:/login-view");
        //将login-view转到login页面
        registry.addViewController("/login-view").setViewName("login");
    }
}

4. 进行Spring Security配置。

WebSecurityConfig.java

package com.aaa.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;

/**
 * spring security配置
 *
 * @author 淮南King
 */
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig
    extends WebSecurityConfigurerAdapter {

    //密码编码器
    @Bean public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

5. 编写dao层和mapper文件

UserDao.java

package com.aaa.dao;

import com.aaa.entity.UserDto;

import java.util.List;

/**
 * 用户信息持久层
 * @author 淮南King
 */
public interface UserDao {
    /**
     * 根据账号查询用户信息
     *
     * @param username 用户姓名
     * @return 用户信息
     */
    UserDto getUserByUsername(String username);

    /**
     * 根据用户id查询用户权限
     *
     * @param userId 用户id
     * @return 权限列表
     */
    List<String> findPermissionsByUserId(String userId);

    /**
     * 添加用户
     *
     * @param userDTO 用户信息
     * @return 修改条数
     */
    int addUser(UserDto userDTO);
}

UserMapper.xml

注意:mapper文件放置的位置在application.properties中的mybatis.mapper-locations进行路径设置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aaa.dao.UserDao">

    <select id="getUserByUsername" parameterType="String" resultType="com.aaa.entity.UserDto">
        select id,username,password,fullname,mobile from t_user where username = #{username}
    </select>

    <select id="findPermissionsByUserId" parameterType="String" resultType="String">
        SELECT code FROM t_permission WHERE id IN(
            SELECT permission_id FROM t_role_permission WHERE role_id IN(
            SELECT role_id FROM t_user_role WHERE user_id = #{id} ))
    </select>

    <insert id="addUser" parameterType="com.aaa.entity.UserDto">
        INSERT INTO `user_db`.`t_user`(`username`, `password`) VALUES (#{username},#{password})
    </insert>
</mapper>

6. 编写service层

UserService.java

package com.aaa.service;

import com.aaa.dao.UserDao;
import com.aaa.entity.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 用户信息持久业务层
 *
 * @author 淮南King
 * @date 2020-07-21
 */
@Service
public class UserService {

    @Autowired
    UserDao dao;

    public UserDto getUserByUsername(String username) {
        return dao.getUserByUsername(username);
    }

    public List<String> findPermissionsByUserId(String userId) {
        return dao.findPermissionsByUserId(userId);
    }

    /**
     * 添加用户
     * @param userDTO
     * @return
     */
    public int addUser(UserDto userDTO) {
        //获取密码编码器
        PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        //将用户的密码进行编码
        String password = passwordEncoder.encode(userDTO.getPassword());
        //将编码后的密码覆盖到用户信息中
        userDTO.setPassword(password.substring(8));
        //将用户信息持久化到数据库中
        return dao.addUser(userDTO);
    }
}

SpringDataUserDetailsService.java
实现spring-security核心接口,其负载的用户特定数据。

package com.aaa.service;

import com.aaa.dao.UserDao;
import com.aaa.entity.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
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;

/**
 * 实现spring-security核心接口,其负载的用户特定数据。
 *
 * @author 淮南King
 */
@Service
public class SpringDataUserDetailsService implements UserDetailsService {

    @Autowired
    UserDao userDao;

    // 根据账号查询用户信息
    @Override public UserDetails loadUserByUsername(String username) {
        //将来连接数据库根据账号查询用户信息
        UserDto userDto = userDao.getUserByUsername(username);
        //当查询此用户不存在时,将抛出用户名未找到异常
        if (userDto == null) {
            throw new UsernameNotFoundException("No such user found, the user name is: "+username);
        }
        //根据用户id查询权限
        List<String> permissions = userDao.findPermissionsByUserId(userDto.getId());
        //将permissions转为数组
        String[] permissionArray = new String[permissions.size()];
        permissions.toArray(permissionArray);
        UserDetails userDetails =
            User.withUsername(userDto.getUsername()).password(userDto.getPassword()).authorities(permissionArray)
                .build();
        return userDetails;
    }
}

7. 编写controller层

LoginController.java
用于登录注册

package com.aaa.controller;

import com.aaa.entity.UserDto;
import com.aaa.service.UserService;
import com.aaa.util.SecurityUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 淮南King
 */
@RestController
public class LoginController {

    @Resource private UserService service;

    @RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})
    public ModelAndView loginSuccess(){
        //获取当前线程的SecurityContext
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获取当前线程中用户的名称,将名称传递至页面
        Map<String,Object> attributes = new HashMap<>();
        attributes.put("username",SecurityUtil.getUserNameByAuthentication(authentication));
        return new ModelAndView("menu",attributes);
    }

    @PostMapping("/user/register")
    public String register(UserDto userDto) {
        service.addUser(userDto);
        return userDto.getUsername()+"注册成功";
    }
    @GetMapping("/register")
    public ModelAndView registerView() {
        return new ModelAndView("register");
    }

}

AuthController.java
用于资源访问

package com.aaa.controller;

import com.aaa.util.SecurityUtil;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 淮南King
 * @date 2020-07-21
 */
@RestController
@RequestMapping("/resource")
public class AuthController {

    /**
     * 测试资源1
     * 拥有p1权限才可以访问
     *
     * @return
     */
    @GetMapping(value = "/r1", produces = {"text/plain;charset=UTF-8"})
    @PreAuthorize("hasAuthority('p1')")
    public String resource1() {
        //获取当前线程的SecurityContext
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获取当前线程的名称
        return SecurityUtil.getUserNameByAuthentication(authentication) + " 访问资源1";
    }

    /**
     * 测试资源2
     * 拥有p2权限才可以访问
     *
     * @return
     */
    @GetMapping(value = "/r2", produces = {"text/plain;charset=UTF-8"})
    @PreAuthorize("hasAuthority('p2')")
    public String resource2() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return SecurityUtil.getUserNameByAuthentication(authentication) + " 访问资源2";
    }

    /**
     * 测试资源3
     * 拥有p3权限才可以访问
     *
     * @return
     */
    @GetMapping(value = "/r3", produces = {"text/plain;charset=UTF-8"})
    @PreAuthorize("hasAuthority('p3')")
    public String resource3() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return SecurityUtil.getUserNameByAuthentication(authentication) + " 访问资源3";
    }
}

附:实体类与帮助类

实体类

UserDto.java

package com.aaa.entity;

/**
 * DTO:与数据库保持一致<br>
 * 用户信息
 * @author 淮南King
 */
public class UserDto {
    /**
     * 用户id
     */
    private String id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 用户密码
     */
    private String password;
    /**
     * 用户角色ID
     */
    private Integer roleId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }
}

PermissionDto.java

package com.aaa.entity;
/**
 *  权限信息
 * @author 淮南King
 */
public class PermissionDto {
    /**
     * 权限id
     */
    private String id;
    /**
     * 权限代号
     */
    private String code;
    /**
     * 权限描述
     */
    private String description;
    /**
     * 路径
     */
    private String url;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

帮助类

SecurityUtil.java

package com.aaa.util;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;

/**
 * Security帮助类
 * @author 淮南King
 * @date 2020-07-21
 */
public class SecurityUtil {

    /**
     * 根据当前执行线程的SecurityContext获取用户名称
     * @param authentication 当前认证通过的用户身份
     * @return 用户名
     */
    public static String getUserNameByAuthentication(Authentication authentication){
        String username = null;
        //用户身份
        Object principal = authentication.getPrincipal();
        if(principal == null){
            return "匿名";
        }
        if(principal instanceof UserDetails){
            UserDetails userDetails = (UserDetails)principal;
            username = userDetails.getUsername();
        }else{
            username = principal.toString();
        }
        return username;
    }
}