欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot 整合 Spring Security

程序员文章站 2022-04-19 22:32:35
...

Spring Boot 整合 Spring Security

1. Spring Security 简介

Spring Security 是一个功能强大且可高度自定义的身份验证和访问控制框架。它是保护基于 Spring 的应用程序的事实上的标准。

和 Shiro 相比:

  • Spring Security 基于 Spring 开发,项目中如果使用 Spring 作为基础,配合 Spring Security 做权限更加方便;

  • Shiro 依赖性低,不需要任何框架和容器,可以独立运行,Spring Security 依赖于 Spring 容器。

2. Spring Boot 整合 Spring Security 流程

  1. 导入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
  2. 开启权限控制

    为 Spring Security 创建一个配置类,用来进行身份验证和权限认证,使用 @EnableWebSecurity 来开启 Spring Security 的权限控制。

    /**
     * @author beastars
     */
    @EnableWebSecurity // 开启权限控制
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Resource
        private UserDetailsService userDetailsService;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
             // 关闭 csrf:跨站请求伪造,默认只能通过post方式提交logout请求
            http.csrf().disable();
    
            // 开启自动配置的登录功能
            http.formLogin()
                    .loginPage("/toLogin") // 设置登陆页面为自定义的 /toLogin 路径
                    .failureForwardUrl("/fail") // 设置登录失败后跳转失败页面
                    .successForwardUrl("/"); // 登录成功后跳转到首页
    
            http.logout().logoutSuccessUrl("/"); // 开启注销功能,注销成功后跳转到 / 路径
    
            // 开启记住我功能,cookie 默认保存两周
            // rememberMeParameter:前端 记住我 功能的按钮的 name 属性
            http.rememberMe().rememberMeParameter("remember"); 
    
            // 设置授权规则
            http.authorizeRequests()
                    .antMatchers("/").permitAll() // 设置 / 路径都可以访问
                    .antMatchers("/fail").permitAll() // 设置失败跳转页面都可以访问
                    .antMatchers("/vip1/**").hasRole("guest") // 设置 /vip1/** 路径只有 guest 用户才能访问
                    .antMatchers("/vip2/**").hasRole("admin") // 设置 /vip2/** 路径只有 admin 用户才能访问
                    .antMatchers("/vip3/**").hasAnyRole("admin", "guest") // 设置 /vip3/** 路径 guest 和 admin 用户都能访问
            ;
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 定义认证规则
            auth.userDetailsService(userDetailsService)
                    .passwordEncoder(passwordEncoder()); // passwordEncoder是对密码的加密处理
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    
  3. 定义实体类

    /**
     * @author beastars
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
        private String role;
    }
    
  4. 创建一个实现了 UserDetailsService 接口的类,用于传输用户信息进行登录。

    /**
     * @author beastars
     */
    @Service
    public class UserService implements UserDetailsService {
        @Autowired
        private JdbcTemplate jdbcTemplate; // 此处偷懒直接使用 JdbcTemplate 来操作数据库
    
        @Override
        public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
            User user = queryByName(name); // 查找用户
    
            if (user == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            String role = user.getRole(); // 获取角色
            ArrayList<GrantedAuthority> authorities = new ArrayList<>();
            // 角色必须以`ROLE_`开头,数据库中没有,则在这里加
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
            // 数据库密码是明文, 需要加密进行比对
            return new org.springframework.security.core.userdetails.User(
                    user.getName(),
                    new BCryptPasswordEncoder().encode(user.getPwd()),
                    authorities
            );
        }
    
        public User queryByName(String name) {
            String sql = "SELECT * FROM USER WHERE NAME = ?";
            User user = null;
            try {
                user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), name);
            } catch (DataAccessException e) {
                System.out.println("用户名不存在");
            }
    
            return user;
        }
    }
    
  5. 定义路由转发器

    /**
     * @author beastars
     */
    @Controller
    public class RouteController {
    
        @RequestMapping({"/", "/index"})
        public String index() {
            return "index";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin() {
            return "login";
        }
    
        @RequestMapping("/fail")
        public String fail() {
            return "fail";
        }
    
        @RequestMapping("/vip1/{id}")
        public String vip1(@PathVariable int id) {
            return "vip1/" + id;
        }
    
        @RequestMapping("/vip2/{id}")
        public String vip2(@PathVariable int id) {
            return "vip2/" + id;
        }
    
        @RequestMapping("/vip3/{id}")
        public String vip3(@PathVariable("id")int id) {
            return "vip3/" + id;
        }
    }
    
相关标签: spring boot