Springsecurity(二)

1. security完成授权。

授权: 把当前用户具有的权限和对应的资源绑定的过程。授权一定发生在认证后。

定义一些资源接口

package com.zql.controller;


import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
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;

/**
 * @program: spring-boot01
 * @description:
 * @author: 
 * @create: 2024-07-27 11:37
 **/
@RestController
@RequestMapping("test")
public class test01 {
    @GetMapping("info")
    public Authentication info(){
        //获取SecuityContext对象
        SecurityContext context = SecurityContextHolder.getContext();
        //把用户信息封装到Authentication对象中
       Authentication authentication = context.getAuthentication();
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        System.out.println(principal.getUsername());
        return authentication;
    }
    @GetMapping("insert")
    public String insert(){
        System.out.println("添加用户");
        return "添加用户";
    }
    @GetMapping("delete")
    public String delete(){
        System.out.println("删除用户");
        return "删除用户";
    }
    @GetMapping("update")
    public String update(){
        System.out.println("修改用户");
        return "修改用户";
    }
    @GetMapping("select")
    public String select(){
        System.out.println("查询用户");
        return "查询用户";
    }
}

修改配置类

package com.zql.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @program: spring-boot01
 * @description: Security configuration class
 * @author: 
 * @create: 2024-07-27 10:58
 **/
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("zql")
                .password(passwordEncoder().encode("123456"))
                .roles("admin")
                .authorities("test:select","test:insert","test:update")
                .and()
                .withUser("zql1")
                .password(passwordEncoder().encode("123456"))
                .roles("user")
                .authorities("test:select","test:insert","test:update","test:delete");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                // 登录页面
                .loginPage("/login.html")
                // 登录处理地址
                .loginProcessingUrl("/login")
                // 登录成功后默认跳转地址
                .successForwardUrl("/success")
                .failureForwardUrl("/error")
                .permitAll();
        //资源和权限绑定
        http.authorizeRequests().
                antMatchers("/test/select").hasAnyAuthority("test:select")
                .antMatchers("/test/insert").hasAnyAuthority("test:insert")
                .antMatchers("/test/update").hasAnyAuthority("test:update")
                .antMatchers("/test/delete").hasAnyAuthority("test:delete");

        http.csrf().disable();
        http.authorizeRequests().anyRequest().authenticated();
    }


}

1.2 使用注解完成授权

上面的授权代码比较麻烦。 我们可以使用注解完成授权的过程。

开启security授权的注解驱动

在资源上使用注解

package com.zql.controller;

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

/**
 * @program: spring-boot-secuity02
 * @description:
 * @author: 
 * @create: 2024-07-27 14:36
 **/
@RestController()
@RequestMapping("/test")
public class TestController {
    @GetMapping("info")
    /**
     * 获取当前认证信息。
     *
     * 本方法通过SecurityContextHolder获取当前的SecurityContext,进而得到Authentication对象。
     * 这个对象包含了当前用户的认证信息,如用户名、权限等。方法返回这个Authentication对象,
     * 可以用于进一步的权限检查或用户信息获取。
     *
     * @return 当前的Authentication对象,包含了用户的认证信息。
     */
    public Authentication info() {
        // 从SecurityContextHolder中获取当前的SecurityContext
        //获取SecuityContext对象
        SecurityContext context = SecurityContextHolder.getContext();
        // 从SecurityContext中获取当前的Authentication对象
        //把用户信息封装到Authentication对象中
        Authentication authentication = context.getAuthentication();
        // 将Authentication对象中的用户主体信息转换为UserDetails类型
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        // 打印用户名,用于调试或日志记录
        System.out.println(principal.getUsername());
        // 返回Authentication对象,供外部使用
        return authentication;
    }

    @PostMapping("/aaa")
    public String error(){
        return "redirect:/aaa.html";
    }
    @GetMapping("insert")
    @PreAuthorize("hasAnyAuthority('test:insert')")
    public String insert(){
        System.out.println("添加用户");
        return "添加用户";
    }
    @GetMapping("delete")
    @PreAuthorize("hasAnyAuthority('test:delete')")
    public String delete(){
        System.out.println("删除用户");
        return "删除用户";
    }

    @GetMapping("update")
    @PreAuthorize("hasAnyAuthority('test:update')")
    public String update(){
        System.out.println("修改用户");
        return "修改用户";
    }
    @GetMapping("select")
    @PreAuthorize("hasAnyAuthority('test:select')")
    public String select(){
        System.out.println("查询用户");
        return "查询用户";
    }
    @GetMapping("export")
    @PreAuthorize("hasAnyAuthority('test:export')")
    public String export(){
        System.out.println("导出用户");
        return "导出用户";
    }

}

1.3 权限不足跳转指定页面

权限不足跳转的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
权限不足, 请联系管理员!!!!!!!!
</body>
</html>

 修改配置类

package com.zql.config;


import com.zql.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @Author:
 * @Description:
 * @Date: Create in 10:43 2024/7/27
 * 如果springboot的版本2.7.0以上
 */
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    //把输入的密码经过密码加密器加密后 数据库中的密码对比
    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
        return passwordEncoder;
    }

    @Autowired
    private MyUserDetailService userDetailService;
    //配置文件中的账号和密码失效
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                //登录页面;
                .loginPage("/login.html")
                //登录的处理路径 默认 /login
                .loginProcessingUrl("/login")
                .successForwardUrl("/success") //登录成功转发的路径 必须为post请求
                .failureForwardUrl("/fail") //登录失败转发的路径 必须为post请求
                .permitAll(); //上面的请求路径无需认证

        //指定权限不足跳转的页面
        http.exceptionHandling().accessDeniedPage("/403.html");

        http.csrf().disable();//禁用跨域伪造请求的过滤器
        //除了上的请求,其他请求都需要认证
        http.authorizeRequests().anyRequest().authenticated();

    }
}

2.【源码分析】spring Security认证授权--了解

为什么需要分析认证得流程?

我们要通过数据库进行认证和授权。

2.1 结构总览

Spring security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。根据前边知识的学习,可以通过Filter或AoP等技术来实现,SpringSecurity对web资源的保护是靠==Filter=='实现的,所以从这个Filter来入手,逐步深入Spring Security 原理。当初始化Spring Security时,会创建一个名为SpringSecurityFilterChain的 Servlet过滤器,类型为org.springframework.security.web.FilterChainProxy,它实现了javax.servlet.Filter,因此外部的请求会经过此类,下图是 Spring Security过虑器链结构图:

上图说明:

FilterchainProxy是一个代理,真正起作用的是FilterChainProxy 中securityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它们是Spring Security核心,各有各的职责,但他们并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理下图是 FilterChainProxy相关类的UML图示

2.2 过滤器链中主要的几个过滤器及其作用

2.2.1 SecurityContextPersistenceFi1ter

这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截器),会在请求开始时从配置好的 SecurityContextRepesitory 中获取SecurityContext,然后把它设置给securityContextHolder.在请求完成后将SecurityContextHolder持有的SecurityContext再保存到配置好的SecurityContextRepository ,同时清除securityContextHolder所持有的SecurityContext;

2.2.2 UsernamePasswordAuthenticationFilter

用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的AuthenticationSuccessHandler和AuthenticationFailureHandler,这些都可以根据需求做相关改变;

2.2.3 FilterSecurityInterceptor

是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问;

2.2.4 ExceptionTranslationFilter

能够捕获来自Filterchain所有的异常,并进行处理。但是它只会处理两类异常:AuthenticationException和 AccessDeniedException,其它的异常它会继续抛出。

2.3【源码分析】Spring security 认证工作流程

UsernamePasswordAuthenticationFilter (attemptAuthentication)

ProviderManager (authenticate) DaoAuthenticationProvider (retrieveUser) AbstractUserDetailsAuthenticationProvider (authenticate)

2.3.1 认证流程图

查询数据库进行比对。

查询用户信息的代码--->UserDetailsService中loadUserByUsername该方法。 我们只需要重写该方法即可。

3. 自定义UserDetailsService接口类

自定义service

package com.zql.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zql.eneity.Permission;
import com.zql.eneity.User;
import com.zql.mapper.PermissionMapper;
import com.zql.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @program: spring-boot-secuity02
 * @description:
 * @author: 
 * @create: 2024-07-29 14:57
 **/
@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据账号查询用户信息--username必须唯一
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.eq("username",username);
        User user = userMapper.selectOne(wrapper);
        //判断用户是否存在
        if(Objects.nonNull(user)){
            //查询当前用户具有的权限
            Collection<Permission> permissions = permissionMapper.selectByUserId(user.getUserid());

            //List<A>--JDK8特性->List<B>
//            List<SimpleGrantedAuthority> list=new ArrayList<>() ;
//            for(Permission  p:permissions){
//                SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(p.getPercode());
//                list.add(simpleGrantedAuthority);
//            }
            List<SimpleGrantedAuthority> collect = permissions.stream().map(item -> new SimpleGrantedAuthority(item.getPercode())).collect(Collectors.toList());
            return new org.springframework.security.core.userdetails.User(username,user.getUserpwd(),collect);
        }
        return null;
    }
}

 修改配置类

package com.zql.config;


import com.zql.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @Author: 
 * @Description:
 * @Date: Create in 10:43 2024/7/27
 * 如果springboot的版本2.7.0以上
 */
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    //把输入的密码经过密码加密器加密后 数据库中的密码对比
    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
        return passwordEncoder;
    }

    @Autowired
    private MyUserDetailService userDetailService;
    //配置文件中的账号和密码失效
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                //登录页面;
                .loginPage("/login.html")
                //登录的处理路径 默认 /login
                .loginProcessingUrl("/login")
                .successForwardUrl("/success") //登录成功转发的路径 必须为post请求
                .failureForwardUrl("/fail") //登录失败转发的路径 必须为post请求
                .permitAll(); //上面的请求路径无需认证

        //指定权限不足跳转的页面
        http.exceptionHandling().accessDeniedPage("/403.html");

        http.csrf().disable();//禁用跨域伪造请求的过滤器
        //除了上的请求,其他请求都需要认证
        http.authorizeRequests().anyRequest().authenticated();

    }
}

4. springsecurity整合thymeleaf

模板引擎等价于jsp.

数据库

/*
 Navicat Premium Data Transfer

 Source Server         : gz02
 Source Server Type    : MySQL
 Source Server Version : 80032
 Source Host           : localhost:3306
 Source Schema         : security

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

 Date: 24/11/2023 11:16:37
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission`  (
  `perid` int(0) NOT NULL AUTO_INCREMENT,
  `pername` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `percode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`perid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, '用户查询', 'user:query');
INSERT INTO `sys_permission` VALUES (2, '用户添加', 'user:add');
INSERT INTO `sys_permission` VALUES (3, '用户修改', 'user:update');
INSERT INTO `sys_permission` VALUES (4, '用户删除', 'user:delete');
INSERT INTO `sys_permission` VALUES (5, '用户导出', 'user:export');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `roleid` int(0) NOT NULL AUTO_INCREMENT,
  `rolename` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`roleid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, '管理员');
INSERT INTO `sys_role` VALUES (2, '测试人员');
INSERT INTO `sys_role` VALUES (3, '普通用户');

-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission`  (
  `perid` int(0) NULL DEFAULT NULL,
  `roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (2, 1);
INSERT INTO `sys_role_permission` VALUES (1, 1);
INSERT INTO `sys_role_permission` VALUES (3, 1);
INSERT INTO `sys_role_permission` VALUES (4, 1);
INSERT INTO `sys_role_permission` VALUES (2, 2);
INSERT INTO `sys_role_permission` VALUES (1, 2);
INSERT INTO `sys_role_permission` VALUES (3, 2);
INSERT INTO `sys_role_permission` VALUES (1, 3);
INSERT INTO `sys_role_permission` VALUES (5, 3);

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `userid` int(0) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `userpwd` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '张三', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '郑州');
INSERT INTO `sys_user` VALUES (2, '李四', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '北京');
INSERT INTO `sys_user` VALUES (3, '王五', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '女', '杭州');

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `userid` int(0) NOT NULL,
  `roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2);
INSERT INTO `sys_user_role` VALUES (3, 3);
INSERT INTO `sys_user_role` VALUES (1, 2);

SET FOREIGN_KEY_CHECKS = 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.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ykq</groupId>
    <artifactId>qy174-spring-boot-security03</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>qy174-spring-boot-security03</name>
    <description>qy174-spring-boot-security03</description>

    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--thymeleaf和springsecurity整合的依赖-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </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>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</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>

配置文件

server.port=8080

spring.datasource.url=jdbc:mysql://localhost:3306/thymeleaf?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis-plus.mapper-locations=classpath*:mapper/*Mapper.xml

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

 实体类使用MybatisX-Generator生成就行

dao

public interface PermissionMapper extends BaseMapper<Permission> {

    public List<Permission> selectByUserId(Integer userId);

}

 service类

package com.zql.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zql.eneity.Permission;
import com.zql.eneity.User;
import com.zql.mapper.PermissionMapper;
import com.zql.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @program: spring-boot-secuity02
 * @description:
 * @author: 
 * @create: 2024-07-29 14:57
 **/
@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据账号查询用户信息--username必须唯一
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.eq("username",username);
        User user = userMapper.selectOne(wrapper);
        //判断用户是否存在
        if(Objects.nonNull(user)){
            //查询当前用户具有的权限
            Collection<Permission> permissions = permissionMapper.selectByUserId(user.getUserid());

            //List<A>--JDK8特性->List<B>
//            List<SimpleGrantedAuthority> list=new ArrayList<>() ;
//            for(Permission  p:permissions){
//                SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(p.getPercode());
//                list.add(simpleGrantedAuthority);
//            }
            List<SimpleGrantedAuthority> collect = permissions.stream().map(item -> new SimpleGrantedAuthority(item.getPercode())).collect(Collectors.toList());
            return new org.springframework.security.core.userdetails.User(username,user.getUserpwd(),collect);
        }
        return null;
    }
}

 配置类使用上方那个就行

在templates里加个登录成功后的页面

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/user/query" sec:authorize="hasAuthority('user:query')">查询用户</a><br>
<a href="/user/add" sec:authorize="hasAuthority('user:add')">添加用户</a><br>
<a href="/user/update" sec:authorize="hasAuthority('user:update')">修改用户</a><br>
<a href="/user/delete" sec:authorize="hasAuthority('user:delete')">删除用户</a><br>
<a href="/user/export" sec:authorize="hasAuthority('user:export')">导出用户</a><br>
</body>
</html>

 

package com.zql.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

/**
 * @program: spring-boot01
 * @description:
 * @author: 赵庆龙
 * @create: 2024-07-27 10:01
 **/
@Controller()
public class HelloController {
    @GetMapping("hello")
    public String hello() {
        return "hello";
    }
    @PostMapping("success")
    public String success(){

        return "index";//redirect:index.html
    }
}

这里跳转到成功页面时不要使用重定向 使用上面的方法视图

 

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security提供了强大的身份认证和授权功能,但默认情况下只提供了一种单一的认证方式。如果你需要进行次认证,你可以按照以下步骤进行配置: 1. 创建一个自定义的AuthenticationProvider:你可以实现`AuthenticationProvider`接口创建一个自定义的认证提供者。在该实现中,你可以添加额外的认证逻辑,例如验证手机验证码、指纹等。 2. 配置Spring Security:在Spring Security的配置类中,注册你自定义的AuthenticationProvider。可以使用`AuthenticationManagerBuilder`的`authenticationProvider`方法来注册。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider customAuthenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthenticationProvider); } // 其他配置... } ``` 3. 实现次认证逻辑:在自定义的AuthenticationProvider中,实现`authenticate`方法来执行次认证逻辑。例如,你可以在该方法中调用其他认证接口或者验证用户输入的验证码等。如果认证成功,返回一个`Authentication`对象;如果认证失败,可以抛出`AuthenticationException`异常。 ```java @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 次认证逻辑,例如验证手机验证码 // 如果认证成功,返回一个Authentication对象 // 如果认证失败,可以抛出AuthenticationException异常 } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } } ``` 以上是一个基本的实现示例,你可以根据你的具体需求进行相应的调整和扩展。通过自定义AuthenticationProvider,你可以实现多种不同的认证方式,以满足不同场景下的次认证需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值