美文网首页
springboot3.0.2,security6.0.1,my

springboot3.0.2,security6.0.1,my

作者: 不知不怪 | 来源:发表于2023-02-17 21:59 被阅读0次

    点我下载完整源码

    1 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>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.0.2</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.gzz</groupId>
        <artifactId>spring-security-06</artifactId>
        <version>1.0</version>
        <properties>
            <java.version>17</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    2 简洁的资源鉴权

    package com.gzz.config;
    
    import java.util.List;
    
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Component;
    
    import jakarta.servlet.http.HttpServletRequest;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @summary 鉴权-资源验证处理
     * @author 高振中
     * @date 2023-02-18 22:20:20
     **/
    @Slf4j
    @Component("resourcesCheck")
    public class ResourcesCheck {
        public boolean check(Authentication authentication, HttpServletRequest request) {
            // 如果要解析token就从request中取出就可以了
            // 再如果不使用session,参数authentication也没有用了,只需从token反解出userId然后从缓存中取出authentication
            // 这时可以在Security主配置文件中关闭session
            // 这种方式不用任何注解,就可以对资源(controller中requestMapping的value)也就是请求路径进行最灵活的配置(在数据库中)
            Object principal = authentication.getPrincipal();
            if (principal instanceof UserDetails) {
                SysUser sysUser = (SysUser) principal;
                List<String> resources = sysUser.getResources();
                log.info("sysUser={},resources={},request.getRequestURI()={}", sysUser, resources, request.getRequestURI());
                return resources.contains(request.getRequestURI());
            }
            return false;
        }
    }
    
    2023-02-18 21:42:33,027[INFO][FrameworkServlet.java:554]:Completed initialization in 1 ms
    2023-02-18 21:42:33,111[INFO][HikariDataSource.java:110]:test - Starting...
    2023-02-18 21:42:33,323[INFO][HikariPool.java:565]:test - Added connection com.mysql.cj.jdbc.ConnectionImpl@774f3160
    2023-02-18 21:42:33,325[INFO][HikariDataSource.java:123]:test - Start completed.
    2023-02-18 21:42:35,833[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/error
    2023-02-18 21:42:35,852[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/error
    2023-02-18 21:42:35,866[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/favicon.ico
    2023-02-18 21:42:38,534[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/error
    2023-02-18 21:42:38,560[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/error
    2023-02-18 21:42:38,576[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/favicon.ico
    2023-02-18 21:43:02,813[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/user/add
    2023-02-18 21:43:09,627[INFO][ResourcesCheck.java:29]:sysUser=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]],resources=[/user/add, /user/update],request.getRequestURI()=/user/list
    2023-02-18 21:43:22,458[INFO][LogoutSuccess.java:23]:authentication=UsernamePasswordAuthenticationToken [Principal=com.gzz.config.SysUser [Username=高振中, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=1E935E5AD193CDB5C1F64515034A0216], Granted Authorities=[ROLE_USER]]
    
    

    3 建表

    CREATE TABLE `user`  (
      `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
      `code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '编码',
      `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',
      `password` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
      `roles` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色集',
      `resources` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '资源集',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    
    INSERT INTO `user` VALUES (1, 'zhang', '张三', '$2a$10$JejfDoeJ7dn/xUPI051JDO1Jr1H/9MnlXqa7GChitOqlcSfjwyxxW', 'ROLE_ADMIN,ROLE_USER', '/user/add,/user/update,/user/list,/user/delete');
    INSERT INTO `user` VALUES (2, 'lisi', '李四', '$2a$10$JejfDoeJ7dn/xUPI051JDO1Jr1H/9MnlXqa7GChitOqlcSfjwyxxW', 'ROLE_ADMIN,ROLE_USER', '/user/add,/user/update,/user/list,/user/delete');
    INSERT INTO `user` VALUES (3, 'gzz', '高振中', '$2a$10$JejfDoeJ7dn/xUPI051JDO1Jr1H/9MnlXqa7GChitOqlcSfjwyxxW', 'ROLE_USER', '/user/add,/user/update');
    INSERT INTO `user` VALUES (4, 'fbb', '范冰冰', '$2a$10$JejfDoeJ7dn/xUPI051JDO1Jr1H/9MnlXqa7GChitOqlcSfjwyxxW', 'ROLE_ADMIN', '/user/list,/user/delete');
    
    1676728473621.png

    4 spring-security主配置类

    package com.gzz.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    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.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler;
    import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
    
    import com.gzz.config.handler.AccessDenied;
    import com.gzz.config.handler.LoginFailure;
    import com.gzz.config.handler.LoginSuccess;
    import com.gzz.config.handler.LogoutSuccess;
    import com.gzz.sys.UserService;
    
    /**
     * @summary spring-security主配置类
     * @author 高振中
     * @date 2023-02-18 22:20:20
     **/
    @Configuration
    public class SecurityConfig {
        @Autowired
        private LoginSuccess loginSuccess;
        @Autowired
        private LoginFailure loginFailure;
        @Autowired
        private AccessDenied accessDenied;
        @Autowired
        private EntryPoint entryPoint;
        @Autowired
        private LogoutSuccess logoutSuccess;
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
            logoutSuccess.setDefaultTargetUrl("/logout_success");
            security//
                    .authorizeHttpRequests(auth -> auth //
                            .requestMatchers("/index.html", "/fonts/**", "/logout_success").permitAll() // 这些请求(url)无需授权
                            .anyRequest().access(expressionManager()))
                    .formLogin((auth) -> auth//
                            .usernameParameter("username") //
                            .passwordParameter("password") //
                            .loginPage("/index.html") //
                            .loginProcessingUrl("/login") //
                            .successHandler(loginSuccess) //
                            .failureHandler(loginFailure) //
                            .permitAll())
                    .logout(auth -> auth//
                            .deleteCookies("JSESSIONID")//
                            .logoutSuccessHandler(logoutSuccess).clearAuthentication(true))
                    .exceptionHandling(exp -> exp//
                            .accessDeniedPage("/index.html")//
                            .accessDeniedHandler(accessDenied)//
                            .authenticationEntryPoint(entryPoint))//
                    .csrf(csrf -> csrf.disable());
            return security.build();
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Autowired
        private UserService service;
    
        public void configureGlobal(@Autowired AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(service).passwordEncoder(passwordEncoder());
        }
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Bean
        public WebExpressionAuthorizationManager expressionManager() {
            DefaultHttpSecurityExpressionHandler expressionHandler = new DefaultHttpSecurityExpressionHandler();
            expressionHandler.setApplicationContext(applicationContext);
            WebExpressionAuthorizationManager authorizationManager = new WebExpressionAuthorizationManager("@resourcesCheck.check(authentication,request)");
            authorizationManager.setExpressionHandler(expressionHandler);
            return authorizationManager;
        }
    }
    
    

    5 UserService

    package com.gzz.sys;
    
    import java.util.Arrays;
    import java.util.List;
    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 org.springframework.util.CollectionUtils;
    import com.gzz.config.SysUser;
    
    /**
     * @类说明 spring-security从数据库加载用户相关的资源数据
     * @author 高振中
     * @date 2023-02-18 22:23:28
     **/
    @Service
    public class UserService implements UserDetailsService {
    
        @Autowired
        private UserDao userDao; // 注入【user】数据访问层
        // 1.不论数据库如何设计,最终都是要解决【用户】拥有哪些【角色】最终分配了多少【资源】的问题,RBAC不在security的讨论范围
        // 2.假定数据已经组装好,最终从数据库里取到的是【用户名,密码,角色集,资源集】这些数据,然后看在security中如何使用
    
        @Override
        public UserDetails loadUserByUsername(String code) {
    
            List<User> users = userDao.list(code);
            if (CollectionUtils.isEmpty(users))
                throw new UsernameNotFoundException("用户不存在");
            User user = users.get(0);
            List<String> roles = Arrays.asList(user.getRoles().split(","));
            List<String> resources = Arrays.asList(user.getResources().split(","));
            return new SysUser(user.getName(), user.getPassword(), roles, resources);
    
        }
    }
    
    

    6 点我下载完整源码

    相关文章

      网友评论

          本文标题:springboot3.0.2,security6.0.1,my

          本文链接:https://www.haomeiwen.com/subject/amjvkdtx.html