• SpringBoot 整合Spring Security


    SpringBoot 整合SpringSecurity

    导入依赖

    <?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>2.0.4.RELEASE</version>
        </parent>
    
        <groupId>cn.blogsx</groupId>
        <artifactId>springboot_spring_security</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <!-- web功能起步依赖-->
            <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>
            <!--thymeleaf依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <!--  mybatis依赖-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!-- druid数据库连接池-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.9</version>
            </dependency>
            <!-- mysql驱动-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    </project>
    

    配置数据库

    配置连接数据库的参数,方便做基于数据库的RABC动态权限管理

    server.port=8080
    
    # 数据库连接相关配置
    spring.datasource.url=jdbc:mysql:///springsecurity?characterEncoding=utf8&useSSL=true
    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=root
    
    # MyBatis注解形式扫描实体类路径
    mybatis.type-aliases-package=cn.blogsx.entity
    
    # MyBatis XML形式配置文件路径
    mybatis.config-locations=classpath:mybatis/mybatis-config.xml
    mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
    
    # 测试基于配置的springSecurity 用户名和密码
    #spring.security.user.name=alex
    #spring.security.user.password=123456
    #spring.security.user.roles=admin
    

    创建SpringSecurity 配置类

    @Configuration //Spring Security 拦截和授权管理配置类
    public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {
        @Autowired
        UserService userService;
    
        @Bean
        PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder(10); //配置加密参数
        }
        @Bean //该bean可结合.sessionManagement().maximumSessions(1)配置完成踢出登陆功能
        HttpSessionEventPublisher httpSessionEventPublisher() {
            return new HttpSessionEventPublisher();
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/admin/**")
                    .hasRole("admin")
                    .antMatchers("/user/**")
                    .hasRole("user")
                    .antMatchers("/db/**")
                    .hasRole("dba")
                    .anyRequest()
                    .authenticated()
                    .and()
                    .rememberMe()//实现记住我功能
                    .key("sxblog")//指定remember-me session加密key(即使重启服务器也可保持用户在线)
                    .and()
                    .formLogin()//表单登陆
                    .loginPage("/login").permitAll() //用户未登陆,配置登陆页面接口或者json提示
                    .loginProcessingUrl("/login").permitAll()//表单提交接口,默认也是login接口
                    .usernameParameter("username")//指定登陆页面或前后端分离下发送请求的字段
                    .passwordParameter("password")//指定登陆页面或前后端分离下发送请求的字段
                    .successHandler(new AuthenticationSuccessHandler() { //定义认证成功后返回json信息
                        @Override
                        public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                            Object principle = authentication.getPrincipal();
                            httpServletResponse.setContentType("application/json;charset=utf-8");
                            PrintWriter out = httpServletResponse.getWriter();
                            httpServletResponse.setStatus(200);
                            Map<String,Object> map = new HashMap<>();
                            map.put("status",200);
                            map.put("msg","登陆成功!");
                            ObjectMapper om = new ObjectMapper();
                            out.write(om.writeValueAsString(map));
                            out.flush();
                            out.close();
                        }
                    })
                    .failureHandler(new AuthenticationFailureHandler() { //登陆认证失败返回json响应信息
                @Override
                public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter out = httpServletResponse.getWriter();
                    httpServletResponse.setStatus(401);
                    Map<String,Object> map = new HashMap<>();
                    map.put("status",401);
                    if(e instanceof LockedException) {
                        map.put("msg","账户被锁定,登陆失败!");
                    } else if (e instanceof BadCredentialsException) {
                        map.put("msg","用户名或密码错误,登陆失败!");
                    }else if (e instanceof DisabledException) {
                        map.put("msg","账户被禁用,登陆失败!");
                    }else if (e instanceof AccountExpiredException) {
                        map.put("msg","账户已过期,登陆失败!");
                    }else if (e instanceof CredentialsExpiredException) {
                        map.put("msg","密码已过期,登陆失败!");
                    } else {
                        e.printStackTrace();
                        map.put("msg","登陆失败!");
                    }
                    ObjectMapper om = new ObjectMapper();
                    out.write(om.writeValueAsString(map));
                    out.flush();
                    out.close();
                }
            })
                    .permitAll()//允许所有人访问登陆接口
                    .and()
                    .logout()//配置注销登陆
                    .logoutUrl("/logout")//配置登出接口
                    .clearAuthentication(true)//清除认证信息
                    .invalidateHttpSession(true)//使Session失效
                    .addLogoutHandler(new LogoutHandler() {
                        @Override
                        public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
                        }
                    })
                    .logoutSuccessHandler(new LogoutSuccessHandler() {
                        @Override
                        public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                            httpServletResponse.setContentType("application/json;charset=utf-8");
                            PrintWriter out = httpServletResponse.getWriter();
                            httpServletResponse.setStatus(200);
                            Map<String,Object> map = new HashMap<>();
                            map.put("status",200);
                            map.put("msg","注销成功!");
                            ObjectMapper om = new ObjectMapper();
                            out.write(om.writeValueAsString(map));
                            out.flush();
                            out.close();
                        }
                    })
                    .and()
                    .csrf()
                    .disable()
                    //关闭csrf安全保护
                    .exceptionHandling() //未登陆状态返回json提示
                    .authenticationEntryPoint((req, resp, authException) -> {
                                resp.setContentType("application/json;charset=utf-8");
                                PrintWriter out = resp.getWriter();
                                out.write("尚未登录,请先登录");
                                out.flush();
                                out.close();
                            }
                    )
                    .and()
                    .sessionManagement()
                    .maximumSessions(1)//只允许一台设备登陆(新的登录踢掉旧的登录)
                    .maxSessionsPreventsLogin(true);
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //            auth.inMemoryAuthentication()
    //                    .withUser("root").password("$2a$10$8XXMNg8WQ8YlSIGGcgnaw./zrf2k6klkqXs0ezawj43VN7uh/m8Wu").roles("ADMIN","DBA")
    //                    .and()
    //                    .withUser("admin").password("$2a$10$8XXMNg8WQ8YlSIGGcgnaw./zrf2k6klkqXs0ezawj43VN7uh/m8Wu").roles("ADMIN","USER")
    //                    .and()
    //                    .withUser("alex").password("$2a$10$8XXMNg8WQ8YlSIGGcgnaw./zrf2k6klkqXs0ezawj43VN7uh/m8Wu").roles("USER");
            auth.userDetailsService(userService);
        }
    }
    
    

    创建相关接口做测试

    @RestController
    public class HelloController {
    
        @RequestMapping("/admin/hello")
        public String adminHello() {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
            System.out.println("IP地址为:"+details.getRemoteAddress());
            return "hello admin1";
        }
        @RequestMapping("/user/hello")
        public String userHello() {
            return "hello user!";
        }
        @RequestMapping("/db/hello")
        public String dbHello() {
            return "hello dba!";
        }
        @RequestMapping("/hello")
        public String hello() {
            return "hello";
        }
    }
    
    
    @Controller
    public class MainController {
        @RequestMapping("/userLogin")
    //    @ResponseBody
        public Map<String,Object> loginPage() {
            HashMap<String,Object> map = new HashMap<>();
            map.put("msg","用户未登录,请登陆!");
            return map;
        }
    
        @RequestMapping("/logout_res")
        @ResponseBody
        public Map<String,Object> logOut() {
            System.out.println("logout_res!");
            HashMap<String,Object> map = new HashMap<>();
            map.put("msg","用户已登出");
            return map;
        }
        @RequestMapping("/login")
        public String login() {
            return "login";
        }
    }
    

    基于数据库做动态权限认证

    实体类

    public class Role {
        private Integer id;
        private String name;
        private String nameZh;
    //省略getter和setter
    }
    
    public class User implements UserDetails {
        private Integer id;
        private String username;
        private String password;
        private Boolean enabled;
        private Boolean locked;
        private List<Role> roles;
    
        public User() {
        }
    
        public User(Integer id, String username, String password, Boolean enabled, Boolean locked, List<Role> roles) {
            this.id = id;
            this.username = username;
            this.password = password;
            this.enabled = enabled;
            this.locked = locked;
            this.roles = roles;
        }
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            for (Role role:roles){
                authorities.add(new SimpleGrantedAuthority(role.getName()));
            }
            return authorities;
        }
    
        @Override
        public String getPassword() {
            return password;
        }
    
        @Override
        public String getUsername() {
            return username;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return !locked;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return enabled;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public List<Role> getRoles() {
            return roles;
        }
    
        public void setRoles(List<Role> roles) {
            this.roles = roles;
        }
    }
    
    

    创建数据库

    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for role
    -- ----------------------------
    DROP TABLE IF EXISTS `role`;
    CREATE TABLE `role`  (
      `id` int(11) NOT NULL,
      `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
      `nameZh` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of role
    -- ----------------------------
    INSERT INTO `role` VALUES (1, 'ROLE_dba', '数据库管理员');
    INSERT INTO `role` VALUES (2, 'ROLE_admin', '系统管理员');
    INSERT INTO `role` VALUES (3, 'ROLE_user', '用户');
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` int(11) NOT NULL,
      `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
      `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
      `enabled` tinyint(1) NULL DEFAULT NULL,
      `locked` tinyint(1) NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES (1, 'root', '$2a$10$8XXMNg8WQ8YlSIGGcgnaw./zrf2k6klkqXs0ezawj43VN7uh/m8Wu', 1, 0);
    INSERT INTO `user` VALUES (2, 'admin', '$2a$10$8XXMNg8WQ8YlSIGGcgnaw./zrf2k6klkqXs0ezawj43VN7uh/m8Wu', 1, 0);
    INSERT INTO `user` VALUES (3, 'alex', '$2a$10$8XXMNg8WQ8YlSIGGcgnaw./zrf2k6klkqXs0ezawj43VN7uh/m8Wu', 1, 0);
    
    -- ----------------------------
    -- Table structure for user_role
    -- ----------------------------
    DROP TABLE IF EXISTS `user_role`;
    CREATE TABLE `user_role`  (
      `id` int(11) NOT NULL,
      `uid` int(11) NULL DEFAULT NULL,
      `rid` int(11) NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Fixed;
    
    -- ----------------------------
    -- Records of user_role
    -- ----------------------------
    INSERT INTO `user_role` VALUES (1, 1, 1);
    INSERT INTO `user_role` VALUES (2, 1, 2);
    INSERT INTO `user_role` VALUES (3, 2, 2);
    INSERT INTO `user_role` VALUES (4, 3, 3);
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    

    源码地址

    https://gitee.com/sixudev/SpringBootStudy

  • 相关阅读:
    2.25
    2.24
    2.22
    influxdb 配置
    mongodb 数据备份
    influxDb数据备份
    Linux 及 git 指令集合
    git 项目 保存至gitee中
    TypeScripte 资料
    SecureCrt 的配色方案
  • 原文地址:https://www.cnblogs.com/sxblog/p/13917674.html
Copyright © 2020-2023  润新知