• SpringBoot集成SpringSecurity


    一.入门(Spring Security在不进行任何配置下默认给出的用户user 密码随项目启动生成随机字符串)

    1.添加依赖

    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
    <version>2.1.5.RELEASE</version>
    </dependency>

    2.访问index首页的时候,系统会默认跳转到login页面进行登录认证

     3.用户名默认是user,密码在项目启动时会自动生成

    4.输入用户和密码即可正常访问

    二.Spring Security用户密码配置其他方式

    1.springboot配置文件中配置

    spring:
      security:
        user:
          name: admin  # 用户名
          password: 123456  # 密码

    2.java代码在内存中配置

     新建Security 核心配置类WebSecurityConfig继承WebSecurityConfigurerAdapter

    @Configuration
    @EnableWebSecurity // 启用Spring Security的Web安全支持
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        /**
         * 用户配置在内存中
         * @param auth
         * @throws Exception
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 在内存中配置用户,配置多个用户调用`and()`方法
            auth.inMemoryAuthentication().passwordEncoder(passwordEncoder())// 指定加密方式
                    .withUser("admin").password(passwordEncoder().encode("123")).roles("ADMIN")
                    .and()
                    .withUser("test").password(passwordEncoder().encode("456")).roles("TEST");
        }
    
    
        /**
         * 配置加密方式
         * @return
         */
        @Bean
        public PasswordEncoder passwordEncoder() {
            //BCryptPasswordEncoder:Spring Security 提供的加密工具,可快速实现加密加盐
            /*return new BCryptPasswordEncoder();*/
            return new PasswordEncoder() {
    
                @Override
                public boolean matches(CharSequence rawPassword, String encodedPassword) {
                    return encodedPassword.equals(encode(rawPassword));
                }
    
                @Override
                public String encode(CharSequence rawPassword) {
                    return Sha1.degest(rawPassword.toString());
                }
            };
        }

    3.从数据库中获取用户账号、密码信息(实际中最常用方式)

    自定义CustomUserDetailsService
    /**
         * 用户配置在数据库中_动态认证
         * @param auth
         * @throws Exception
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
        }

    三. Spring Security 配置 登录处理 与 忽略拦截 

    /**
         * 登录处理
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //开启登录配置
            http.authorizeRequests()
                    // 标识访问 `/index` 这个接口,需要具备`ADMIN`角色
                    .antMatchers("/index").hasRole("ADMIN")
                    // 允许匿名的url - 可理解为放行接口 - 多个接口使用,分割
                    .antMatchers(
                            servicePrefix+"/",
                            servicePrefix+"/csrf",
                            servicePrefix + "/actuator/health/**",
                            servicePrefix + "/auth/login",
                            servicePrefix + "/public/**").permitAll()
                    // 其余所有请求都需要认证
                    .anyRequest().authenticated()
                    .and()
                    // 设置登录认证页面
                    .formLogin().loginPage(servicePrefix + "/auth/login")
                    // 登录成功后的处理器
                    .successHandler(authenticationSuccessHandler)
                    // 登录失败的处理器
                    .failureHandler(authenticationFailHandler)
                    .and()
                    // 配置注销成功的处理
                    .logout().logoutUrl(servicePrefix + "/auth/logout").deleteCookies("SESSIONID", "JSESSIONID", "TGC")
                    .logoutSuccessHandler(myLogoutSuccessHandler)
                    .and()
                    // 配置 Http Basic 验证
                    .httpBasic()
                    .and()
                    //关闭CSRF跨域
                    .csrf().disable();
            // 配置跨域资源共享
            http.cors();
            // 是否允许配置请求缓存
            http.requestCache().disable();
    
        }
    
        /**
         * 忽略拦截
         * @param web
         * @throws Exception
         */
        @Override
        public void configure(WebSecurity web) throws Exception {
            // 设置拦截忽略url或者js/css等静态资源,将不会经过Spring Security过滤器链
            web.ignoring().antMatchers(servicePrefix + "/swagger-ui.html",
                    servicePrefix + "/swagger-resources/**",
                    servicePrefix + "/v2/**",
                    servicePrefix + "/webjars/springfox-swagger-ui/**",
                    "/**/*.html",
                    "/**/*.css", "/**/*.js",
                    "/**/*.png", "/**/*.jpg", "/**/*.jpeg",
                    "/**/*.ico","/**/*.svg", "/**/*.ttf","/**/*.woff", "/**/*.woff2");
        }

     最后,附上完整的security配置代码

    1.WebSecurityConfig配置

    @Configuration
    @EnableWebSecurity // 启用Spring Security的Web安全支持
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Value("${spring.mvc.servlet.path}")
        private String servicePrefix;
    
        @Resource
        private AuthenticationSuccessHandler authenticationSuccessHandler;
    
        @Resource
        private AuthenticationFailHandler authenticationFailHandler;
    
        @Resource
        private MyLogoutSuccessHandler myLogoutSuccessHandler;
    
        @Resource
        private CustomUserDetailsService customUserDetailsService;/**
         * 用户配置在内存中_静态认证
         * @param auth
         * @throws Exception
         */
        /*@Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 在内存中配置用户,配置多个用户调用`and()`方法
            auth.inMemoryAuthentication().passwordEncoder(passwordEncoder())// 指定加密方式
                    .withUser("admin").password(passwordEncoder().encode("123")).roles("ADMIN")
                    .and()
                    .withUser("test").password(passwordEncoder().encode("456")).roles("TEST");
        }*/
    
        /**
         * 用户配置在数据库中_动态认证
         * @param auth
         * @throws Exception
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
        }
    
        /**
         * 配置加密方式
         * @return
         */
        @Bean
        public PasswordEncoder passwordEncoder() {
            //BCryptPasswordEncoder:Spring Security 提供的加密工具,可快速实现加密加盐
            /*return new BCryptPasswordEncoder();*/
            return new PasswordEncoder() {
                @Override
                public boolean matches(CharSequence rawPassword, String encodedPassword) {
                    return encodedPassword.equals(encode(rawPassword));
                }
    
                @Override
                public String encode(CharSequence rawPassword) {
                    return Sha1.degest(rawPassword.toString());
                }
            };
        }
    
        /**
         * 登录处理
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //开启登录配置
            http.authorizeRequests()
                    // 标识访问 `/index` 这个接口,需要具备`ADMIN`角色
                    .antMatchers("/index").hasRole("ADMIN")
                    // 允许匿名的url - 可理解为放行接口 - 多个接口使用,分割
                    .antMatchers(
                            servicePrefix+"/",
                            servicePrefix+"/csrf",
                            servicePrefix + "/actuator/health/**",
                            servicePrefix + "/auth/login",
                            servicePrefix + "/public/**").permitAll()
                    // 其余所有请求都需要认证
                    .anyRequest().authenticated()
                    .and()
                    // 设置登录认证页面
                    .formLogin().loginPage(servicePrefix + "/auth/login")
                    // 登录成功后的处理器
                    .successHandler(authenticationSuccessHandler)
                    // 登录失败的处理器
                    .failureHandler(authenticationFailHandler)
                    .and()
                    // 配置注销成功的处理
                    .logout().logoutUrl(servicePrefix + "/auth/logout").deleteCookies("SESSIONID", "JSESSIONID", "TGC")
                    .logoutSuccessHandler(myLogoutSuccessHandler)
                    .and()
                    // 配置 Http Basic 验证
                    .httpBasic()
                    .and()
                    //关闭CSRF跨域
                    .csrf().disable();
            // 配置跨域资源共享
            http.cors();
            // 是否允许配置请求缓存
            http.requestCache().disable();
    
        }
    
        /**
         * 忽略拦截
         * @param web
         * @throws Exception
         */
        @Override
        public void configure(WebSecurity web) throws Exception {
            // 设置拦截忽略url或者js/css等静态资源,将不会经过Spring Security过滤器链
            web.ignoring().antMatchers(servicePrefix + "/swagger-ui.html",
                    servicePrefix + "/swagger-resources/**",
                    servicePrefix + "/v2/**",
                    servicePrefix + "/webjars/springfox-swagger-ui/**",
                    "/**/*.html",
                    "/**/*.css", "/**/*.js",
                    "/**/*.png", "/**/*.jpg", "/**/*.jpeg",
                    "/**/*.ico","/**/*.svg", "/**/*.ttf","/**/*.woff", "/**/*.woff2");
        }
    }

    2.自定义 CustomUserDetailsService 

    @Component
    public class CustomUserDetailsService implements UserDetailsService {
    
        @Resource
        private UserMapper userMapper;
    
        @Override
        public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
    
            UserInfo loginUser = userMapper.selectOneByUserLoginId(userName);
            if (loginUser == null) {
                throw new UsernameNotFoundException("用户名为" + userName + "的用户不存在");
            }
    
            List<Role> roles = loginUser.getRoles();
            List<SimpleGrantedAuthority> authoritys = this.getAuthority(roles);
    
            /*
            这里构建一个Security自带的User对象返回,其构造方法:
            username: 用户登录名
            password: 用户登录密码
            enabled: 用户是启用还是禁用 true-启用 false-禁用
            accountNonExpired: 用户的帐户是否已过期 true-有效 false-过期
            accountNonLocked: 用户是锁定还是解锁 true-未锁定 false-锁定
            credentialsNonExpired: 用户的凭据(密码)是否已过期 true-凭据有效 false-凭据无效
            authorities :用户权限(角色)集合
            */
            User userDetails = new User(loginUser.getUserLoginId(),loginUser.getPassword(), loginUser.getStatus() != 0,true,true,true,authoritys);
            return userDetails;
        }
    
        private List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
            List<SimpleGrantedAuthority> authoritys = new ArrayList<>();
            for (Role role : roles) {
                authoritys.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
            }
            return authoritys;
        }
    }

    3.登陆成功处理器

    @Component
    public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    
        @Resource
        private ObjectMapper objectMapper;
    
        @Resource
        private UserMapper userMapper;
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            String username = userDetails.getUsername();
            UserInfo userInfo = userMapper.selectOneByUserLoginId(username);
    
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(RestResponse.success(userInfo)));
    
        }
    }

    4.登陆失败处理器

    @Component
    public class
    AuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {
    
        @Resource
        private ObjectMapper objectMapper;
    
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(RestResponse.AUTHC_ERROR));
        }
    
    }

    5.注销成功处理器

    @Component
    public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    
        @Resource
        private ObjectMapper objectMapper;
    
        @Override
        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    
            request.getSession().invalidate();
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(RestResponse.notify("注销成功")));
    
        }
    }

     ......

    springsecurity方法级权限注解详见链接: https://www.cnblogs.com/Baker-Street/p/12893414.html

  • 相关阅读:
    ajaxFileUpload 实现多文件上传(源码)
    Springboot 热部署的两种方式
    基于树莓派3B+Python3.5的OpenCV3.4的配置教程
    Shiro 架构原理
    Cron表达式
    SpringBoot中Scheduled代码实现
    Linus安装mysql8
    查看虚拟机CENTOS7 的 IP 地址和命令
    linux vi保存退出命令 (如何退出vi)
    Linux常用命令大全
  • 原文地址:https://www.cnblogs.com/Baker-Street/p/12810275.html
Copyright © 2020-2023  润新知