SpringBoot Security从入门到实战示例教程

目录
  • 前言
  • 入门
    • 测试接口
    • 增加依赖
  • 自定义配置
    • 配置密码加密方式
    • 配置AuthenticationManagerBuilder 认证用户、角色权限
    • 配置HttpSecurity Url访问权限
    • 自定义successHandler
    • 自定义failureHandler
    • 自定义未认证处理
    • 自定义权限不足处理
    • 自定义注销登录
  • 前后端分离场景
    • 提供登录接口
    • 自定义认证过滤器
    • 鉴权
      • 1.注解鉴权
      • 2.自定义Bean动态鉴权
      • 3.扩展默认方法自定义扩展根对象SecurityExpressionRoot
    • 登出
    • 跨域
    • 全局配置

前言

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。提供了完善的认证机制和方法级的授权功能。是一款非常优秀的权限管理框架。它的核心是一组过滤器链,不同的功能经由不同的过滤器。这篇文章给大家讲解SpringBoot Security从入门到实战,内容如下所示:

入门

测试接口

假设我们用下面的接口做权限测试。

@RestController
public class LakerController {
    @GetMapping("/laker")
    public String laker() {
        return IdUtil.simpleUUID();
    }
    @GetMapping("/laker/q")
    public String lakerQ() {
        return IdUtil.simpleUUID();
    }
}

浏览器访问:http://localhost:8080/laker,结果如下:

增加依赖

pom.xml,添加 spring-boot-starter-securtiy 依赖。

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

再次访问http://localhost:8080/laker,结果如下:

简要解析

我们访问http://localhost:8080/laker,security判断我们没有登录,则会302重定向http://localhost:8080/login(默认)

  • security会返回一个默认的登录页。
  • 默认用户名为:user,密码在服务启动时,会随机生成一个,可以查看启动日志如下:

2022-05-02 21:01:03.697  INFO 17896 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-05-02 21:01:03.825  INFO 17896 --- [           main] .s.s.UserDetailsServiceAutoConfiguration :

Using generated security password: e53fef6a-3f61-43c3-9609-ce88fd7c0841

当然,可以通过配置文件设置默认的用户名、密码、角色。

spring:
  security:
    user:
      # 默认是 user
      name: laker
      password: laker
      roles:
        - ADMIN
        - TESTER

以上的默认都是可以修改的哈。

判断是否登录使用传统的cookie session模式哈,JSESSIONID E3512CD1A81DB7F2144C577BA38D2D92 HttpOnly true

自定义配置

实际项目中我们的用户、密码、角色、权限、资源都是存储在数据库中的,我们可以通过自定义类继承 WebSecurityConfigurerAdapter,从而实现对 Spring Security 更多的自定义配置。

@Configuration
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
		...
}

配置密码加密方式

必须配置,否则报空指针异常。

   @Bean
    PasswordEncoder passwordEncoder() {
        // 不加密
        return NoOpPasswordEncoder.getInstance();
    }

Spring Security 提供了多种密码加密方案,官方推荐使用 BCryptPasswordEncoder

BCryptPasswordEncoder 使用 BCrypt 强哈希函数,开发者在使用时可以选择提供 strengthSecureRandom 实例。strength 取值在 4~31 之间(默认为 10)。strength 越大,密钥的迭代次数越多(密钥迭代次数为 2^strength)。如果是数据库认证,库里的密码同样也存放加密后的密码。同一密码每次 Bcrypt 生成的结果都会变化不会重复。

配置AuthenticationManagerBuilder 认证用户、角色权限

支持直接配置内存认证模式和配置UserDetailsServiceBean方式

内存认证模式,实际项目不用这个哦。(仅做了解)

 /**
     * 配置用户及其对应的角色
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("123").roles("ADMIN", "USER")
                .and()
                .withUser("laker").password("123").roles("USER");
    }

上面在UserDetailsService的实现之一InMemoryUserDetailsManager中,即存储在内存中。

自定义UserDetailsServiceBean方式,实际项目都是使用这个,可定制化程度高。

步骤一:定义一个LakerUserService实现UserDetailsService,配置成SpringBean。该方法将在用户登录时自动调用。

@Service
public class LakerUserService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // username 就是前端传递的例如 laker 123,即 laker
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("账户不存在!");
        }
        user.setAuthorities(...);
        return user;
    }
}

username

password(加密后的密码)

authorities

返回的Bean中以上3个都不能为空。返回User后由系统提供的 DaoAuthenticationProvider 类去比对密码是否正确。

Spring Security默认支持表单请求登录的源码,UsernamePasswordAuthenticationFilter.java

步骤二:在把自定义的LakerUserService装载进去.

@Autowired
UserService userService;
...
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userService);
}

步骤三:其中我们的业务用户User必须要实现UserDetails接口,并实现该接口中的 7 个方法:

  • getAuthorities():获取当前用户对象所具有的权限信息
  • getPassword():获取当前用户对象的密码

返回的密码和用户输入的登录密码不匹配,会自动抛出 BadCredentialsException 异常。

  • getUsername():获取当前用户对象的用户名
  • isAccountNonExpired():当前账户是否未过期
  • isAccountNonLocked():当前账户是否未锁定
  • 返回了 false,会自动抛出 AccountExpiredException 异常。
  • isCredentialsNonExpired():当前账户密码是否未过期
  • isEnabled():当前账户是否可用
@Data
public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    private List<String> 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;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authoritiesList = new ArrayList<>();
        for (String authority : authorities) {
            authoritiesList.add(new SimpleGrantedAuthority(authority));
        }
        return authoritiesList;
    }
}

配置HttpSecurity Url访问权限

  /**
     * 配置 URL 访问权限
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //
        http    // 1.开启 HttpSecurity 配置
                .authorizeRequests()
                // laker/** 模式URL必须具备laker.query
                .antMatchers("/laker/**").hasAnyAuthority("laker.query")
                // 用户访问其它URL都必须认证后访问(登录后访问)
                .anyRequest().authenticated()
                .and()
                // 2.开启表单登录,前后端分离的时候不用这个
                .formLogin()
                // 未登录时 重定向的url 默认是/login 内置的页面,可以自己自定义哈。一般前后端分离,不用这个
//                .loginPage("/login")
                //
//                .defaultSuccessUrl("/user",true)
//                .usernameParameter("username") // default is username
//                .passwordParameter("password") // default is password
//                .loginPage("/authentication/login") // default is /login with an HTTP get
//                .failureUrl("/authentication/login?failed") // default is /login?error
//                .loginProcessingUrl("/authentication/login/process") // default is /login
                .and()
                // 3.关闭csrf,前后端分离不需要这个。
                .csrf().disable();
                //授权码模式需要 会弹出默认自带的登录框
                http.httpBasic();
        		// 开启注销登录的配置
                http.logout()
                    // 配置注销登录请求URL为"/logout"(默认也就是 /logout)
                    .logoutSuccessUrl("/logout")
                    .clearAuthentication(true) // 清除身份认证信息
                    .invalidateHttpSession(true) // 使 session 失效;
    }
  • formLogin() 表示开启表单登录
  • **defaultSuccessUrl()**表示默认登录验证成功跳转的url,默认重定向到上次访问未成功的,如果没有则重定向到/.
  • loginProcessingUrl() 方法配置登录接口为“/login”,即可以直接调用“/login”接口,发起一个 POST 请求进行登录,登录参数中用户名必须为 username,密码必须为 password,配置 loginProcessingUrl 接口主要是方便 Ajax 或者移动端调用登录接口。

anyRequest          |   匹配所有请求路径
    access              |   SpringEl表达式结果为true时可以访问
    anonymous           |   匿名可以访问 所有人都能访问,但是带上 token访问后会报错403
    denyAll             |   用户不能访问 所有人都能访问,包括带上 token 访问
    fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
    hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
    hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
    hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
    hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
    hasRole             |   如果有参数,参数表示角色,则其角色可以访问
    permitAll           |   用户可以任意访问
    rememberMe          |   允许通过remember-me登录的用户访问
    authenticated       |   用户登录后可访问

自定义successHandler

登录成功后默认是重定向url,我们可以自定义返回json用于前后端分离场景以及其他逻辑,例如成功之后发短信等。

http.formLogin().successHandler((req, resp, authentication) -> {
    // 发短信哈
    Object principal = authentication.getPrincipal();
    resp.setContentType("application/json;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.write(new ObjectMapper().writeValueAsString(principal));
    out.flush();
    out.close();
})

自定义failureHandler

登录失败回调

http.formLogin().failureHandler((req, resp, e) -> {
    resp.setContentType("application/json;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.write(e.getMessage());
    out.flush();
    out.close();
})

自定义未认证处理

http.exceptionHandling()
.authenticationEntryPoint((req, resp, authException) -> {
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write("尚未登录,请先登录");
            out.flush();
            out.close();
        }
);

自定义权限不足处理

http.exceptionHandling()
				//没有权限,返回json
				.accessDeniedHandler((request,response,ex) -> {
					response.setContentType("application/json;charset=utf-8");
					response.setStatus(HttpServletResponse.SC_FORBIDDEN);
					PrintWriter out = response.getWriter();
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("code",403);
					map.put("message", "权限不足");
					out.write(objectMapper.writeValueAsString(map));
					out.flush();
					out.close();
				})

自定义注销登录

.logout()
.logoutUrl("/logout")
.logoutSuccessHandler((req, resp, authentication) -> {
    resp.setContentType("application/json;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.write("注销成功");
    out.flush();
    out.close();
})

前后端分离场景

上面的都是入门的,实际项目中一般都是前后端分离的,在登录时都是自定义登录接口,例如登录接口是restful风格,增加了其他的验证码参数,还使用jwt来完成登录鉴权等。

提供登录接口

该接口需要在配置当中放行,未授权访问需要授权的请求时,会返回401或者403状态码,前端可以根据这个进行路由提示处理。

@RestController
public class LoginController {
   @Autowired
   LoginService ...
   @PostMapping("/login")
   public  login(@RequestBody Login login){
       ...
       return token;
   }
}

Service层创建UsernamePasswordAuthenticationToken对象,把用户名和密码封装成Authentication对象.

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Override
    public  doLogin(Login login) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password;
        Authentication  authenticate
        try {         // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
             authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }

        if (Objects.isNull(authenticate)) {
            //用户名密码错误
            throw new ServicesException(...);
        }
        User authUser = (User) authenticate.getPrincipal();
        String token = JwtUtil.createJWT(username);
        Map<String, String> map = new HashMap<>();
        map.put("token", token);
        return map;
    }
}

自定义认证过滤器

坊间有2种实现方式。

方式一:继承UsernamePasswordAuthenticationFilter的写法需要使用登陆成功处理器、失败处理器等,还是需要按照security这一套来玩。

Spring Security默认支持表单请求登录的源码UsernamePasswordAuthenticationFilter.java

方式二:使用Filter的写法没有任何限制怎么玩都行,比如说添加其他参数验证码,返回json,token鉴权等。

@Component
public class LakerOncePerRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(token) )
        {
            // 校验token ...
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, authorities;
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));                                     SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}                                                                                                           //3、在UsernamePasswordAuthenticationFilter前添加认证过滤器
http.addFilterBefore(lakerOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);

鉴权

1.注解鉴权

  • SpringSecurity配置类中开启方法级的认证
  • 使用 @PreAuthorize注解在方法或者类
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
@RestController
public class Controller {
    @GetMapping("/hello")
    @PreAuthorize("hasAnyAuthority('laker.query')")
    public String test() {
}

2.自定义Bean动态鉴权

因为@PreAuthorize支持SpringEL表达式,所以可以支持自定义SpringBean动态鉴权。

  • 先自定义一个SpringBean。
  • 使用 @PreAuthorize注解在方法或者类配合@PreAuthorize(“@rbacService.hasPermission(‘xx’)”)
@Component("rbacService")
public class LakerRBACService {
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object principal = authentication.getPrincipal();
        if (principal instanceof UserDetails) {
            UserDetails userDetails=(UserDetails)principal;

            /**
             * 该方法主要对比认证过的用户是否具有请求URL的权限,有则返回true
             */
            //本次要访问的资源
              SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(request.getMethod() + "" + request.getRequestURI());

            //用户拥有的权限中是否包含请求的url
            return userDetails.getAuthorities().contains(simpleGrantedAuthority);
        }
        return false;
    }
        public boolean hasPermission() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        if (principal instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) principal;
            /**
             * 该方法主要对比认证过的用户是否具有请求URL的权限,有则返回true
             */
            //本次要访问的资源
            HttpServletRequest request =((ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes()).getRequest();

            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(request.getRequestURI());
            //用户拥有的权限中是否包含请求的url
            return userDetails.getAuthorities().contains(simpleGrantedAuthority);
        }
        return false;
    }
}
// controller方法
@PreAuthorize("@rbacService.hasPermission()")
public String test() {
}
// 或者高级的全局url鉴权
public class SecurityConfig extends WebSecurityConfigurerAdapter {
         ...
      http.authorizeRequests() //设置授权请求,任何请求都要经过下面的权限表达式处理
          .anyRequest().access("@rbacService.hasPermission(request,authentication)") //权限表达式

3.扩展默认方法自定义扩展根对象SecurityExpressionRoot

https://www.jb51.net/article/245172.htm

1.创建自定义根对象

public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
    public CustomMethodSecurityExpressionRoot(Authentication authentication) {
        super(authentication);
    }
    /**
     * 自定义表达式
     * @param username 具有权限的用户账号
     */
    public boolean hasUser(String... username) {
        String name = this.getAuthentication().getName();
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();
        String[] names = username;
        for (String nameStr : names) {
            if (name.equals(nameStr)) {
                return true;
            }
        }
        return false;
    }
}

2.创建自定义处理器

创建自定义处理器,主要是重写创建根对象的方法。

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
        CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
        root.setThis(invocation.getThis());
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(getTrustResolver());
        root.setRoleHierarchy(getRoleHierarchy());
        root.setDefaultRolePrefix(getDefaultRolePrefix());
        return root;
    }
}

3.配置GlobalMethodSecurityConfiguration
之前我们使用@EnableGlobalMethodSecurity开启全局方法安全,而这些全局方法级别的安全配置就在GlobalMethodSecurityConfiguration配置类中。

可以扩展这个类来自定义默认值,但必须确保在类上指定@EnableGlobalMethodSecurity 注解,否则会bean冲突报错。

@Configuration
// 将EnableGlobalMethodSecurity注解移到这里
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new CustomMethodSecurityExpressionHandler();
    }
}

4.controller使用自定义方法

@PreAuthorize("hasUser('laker','admin')")
public String test() {
    ...
}

登出

http.logout().logoutUrl("/logout").logoutSuccessHandler((request, response, authentication) -> {
            // 删除用户token
    		...
            // 返回json
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            out.write("OK");
            out.flush();
            out.close();
        });

跨域

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.cors();//允许跨域,配置后SpringSecurity会自动寻找name=corsConfigurationSource的Bean
	http.csrf().disable();//关闭CSRF防御
}

@Configuration
public class CrosConfig {
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration cores=new CorsConfiguration();
        cores.setAllowCredentials(true);//允许客户端携带认证信息
        //springBoot 2.4.1版本之后,不可以用 * 号设置允许的Origin,如果不降低版本,则在跨域设置时使用setAllowedOriginPatterns方法
       // cores.setAllowedOrigins(Collections.singletonList("*"));//允许所有域名可以跨域访问
        cores.setAllowedOriginPatterns(Collections.singletonList("*"));
        cores.setAllowedMethods(Arrays.asList("GET","POST","DELETE","PUT","UPDATE"));//允许哪些请求方式可以访问
        cores.setAllowedHeaders(Collections.singletonList("*"));//允许服务端访问的客户端请求头
        // 暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
        cores.addExposedHeader(jsonWebTokenUtil.getHeader());
        // 注册跨域配置
        // 也可以使用CorsConfiguration 类的 applyPermitDefaultValues()方法使用默认配置
        source.registerCorsConfiguration("/**",cores.applyPermitDefaultValues());
        return source;
    }
}

全局配置

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;

    @Autowired
    TokenFilter tokenFilter;

    /**
     * 配置 URL 访问权限
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //
        http    // 1.过滤请求
                .authorizeRequests()
                // 2.对于登录login 验证码captcha 允许访问
                .antMatchers("/login").permitAll()
                // 用户访问其它URL都必须认证后访问(登录后访问)
                .anyRequest().authenticated()
                .and()
                // 3.关闭csrf
                .csrf().disable()
                // 4.基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 5.页面能不能以 frame、 iframe、 object 形式嵌套在其他站点中,用来避免点击劫持(clickjacking)攻击
                .and().headers().frameOptions().disable();
        // 异常处理
        http.exceptionHandling()
                // 未认证返回401
                .authenticationEntryPoint((req, response, authException) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    PrintWriter out = response.getWriter();
                    out.write("尚未登录,请先登录");
                    out.flush();
                    out.close();
                })
                // 没有权限,返回403 json
                .accessDeniedHandler((request, response, ex) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    PrintWriter out = response.getWriter();
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("code", 403);
                    map.put("message", "权限不足");
                    out.write(JSONUtil.toJsonPrettyStr(map));
                    out.flush();
                    out.close();
                });
        // 配置登出
        http.logout().logoutUrl("/logout").logoutSuccessHandler((request, response, authentication) -> {
                // 删除用户token
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            out.write("OK");
            out.flush();
            out.close();
        });
        // 添加JWT filter
        http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 配置用户及其对应的角色
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }
    /**
     * 适用于静态资源的防拦截,css、js、image 等文件
     * 配置的url不会保护它们免受CSRF、XSS、Clickjacking等的影响。
     * 相反,如果您想保护端点免受常见漏洞的侵害,请参阅configure(HttpSecurity)
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**");
    }
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }
}

参考:

https://blog.csdn.net/X_lsod/article/details/122914659

https://blog.csdn.net/godleaf/article/details/108318403

https://blog.csdn.net/qq_43437874/article/details/119543579

到此这篇关于SpringBoot Security从入门到实战示例教程的文章就介绍到这了,更多相关SpringBoot Security入门内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot整合springsecurity与mybatis-plus的简单实现

    1.概述 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架. 它是用于保护基于Spring的应用程序的实际标准. Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权. 与所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求 springboot对于springSecurity提供了自动化配置方案,可以使用更少的配置来使用springsecurity 而在项目开发中,主要用于对用户的

  • SpringBoot整合Security安全框架实现控制权限

    目录 一.前言 介绍: 官网: 优缺点: 案例: 二.环境准备 2.1.数据库表 2.2.导入依赖 2.3.配置文件 2.4.WebSecurityConfig Security的主要配置类: 2.5.Security身份验证 2.6.Security授权 2.7.UserDetailsService 2.7.MacLoginUrlAuthenticationEntryPoint 2.8.MyAccessDeniedHandler 2.9.MyLogoutSuccessHandler 2.10.

  • SpringBoot如何整合Springsecurity实现数据库登录及权限控制

    目录 第一步 第二步是封装一个自定义的类 第三步, 我们需要判断密码啦 总结 我们今天使用SpringBoot来整合SpringSecurity,来吧,不多BB 首先呢,是一个SpringBoot 项目,连接数据库,这里我使用的是mybaties.mysql, 下面是数据库的表 DROP TABLE IF EXISTS `xy_role`; CREATE TABLE `xy_role` ( `xyr_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键i

  • Springboot+SpringSecurity实现图片验证码登录的示例

    这个问题,网上找了好多,结果代码都不全,找了好多,要不是就自动注入的类注入不了,编译报错,要不异常捕获不了浪费好多时间,就觉得,框架不熟就不能随便用,全是坑,气死我了,最后改了两天.终于弄好啦; 问题主要是: 返回的验证码不知道在SpringSecurity的什么地方和存在内存里的比较?我用的方法是前置一个过滤器,插入到表单验证之前. 比较之后应该怎么处理,:比较之后要抛出一个继承了AuthenticationException的异常 其次是捕获验证码错误异常的处理? 捕获到的异常交给自定义验证

  • SpringBoot Security的自定义异常处理

    目录 SpringBoot Security自定义异常 access_denied 方面异常 Invalid access token 方面异常 Bad credentials 方面异常(登陆出错) 其他类 补充 SpringSecurity自定义响应异常信息 SpringBoot Security自定义异常 access_denied 方面异常 原异常 { "error": "access_denied", "error_description"

  • SpringBoot Security从入门到实战示例教程

    目录 前言 入门 测试接口 增加依赖 自定义配置 配置密码加密方式 配置AuthenticationManagerBuilder 认证用户.角色权限 配置HttpSecurity Url访问权限 自定义successHandler 自定义failureHandler 自定义未认证处理 自定义权限不足处理 自定义注销登录 前后端分离场景 提供登录接口 自定义认证过滤器 鉴权 1.注解鉴权 2.自定义Bean动态鉴权 3.扩展默认方法自定义扩展根对象SecurityExpressionRoot 登出

  • Springboot WebFlux集成Spring Security实现JWT认证的示例

    1 简介 在之前的文章<Springboot集成Spring Security实现JWT认证>讲解了如何在传统的Web项目中整合Spring Security和JWT,今天我们讲解如何在响应式WebFlux项目中整合.二者大体是相同的,主要区别在于Reactive WebFlux与传统Web的区别. 2 项目整合 引入必要的依赖: <dependency> <groupId>org.springframework.boot</groupId> <art

  • java开发SpringBoot参数校验过程示例教程

    目录 为什么需要参数校验 SpringBoot中集成参数校验 第一步,引入依赖 第二步,定义要参数校验的实体类 常见的约束注解如下: 第三步,定义校验类进行测试 第四步,体验效果 自定义参数校验 第一步,创建自定义注解 第二步,自定义校验逻辑 第三步,在字段上增加注解 第四步,体验效果 分组校验 第一步:定义分组接口 第二步,在模型中给参数分配分组 第三步,给需要参数校验的方法指定分组 第四步,体验效果 小结 大家好,我是飘渺. 前几天写了一篇SpringBoot如何统一后端返回格式?老鸟们都是

  • Go语言快速入门指针Map使用示例教程

    目录 1. 指针 1.1 指针地址和指针类型 1.2 指针取值 1.3 空指针 1.4 new 的使用 1.5 new与make的区别 2. Map 2.1 什么是Map key,value存储 hash冲突 hash冲突的常见解决方法 开放定址(线性探测)和拉链的优缺点 2.2 Map 定义 2.3 map基本使用 2.4 map的遍历 2.5 map判断某个键是否存在 2.6 map使用delete()函数删除键值对 1. 指针 区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,

  • SpringBoot集成Graphql Query实战示例

    目录 概述 场景模拟 开发实战 创建一个SpringBoot项目 建立Java实体类 编写Schema文件 编写业务逻辑 配置Graphql 端点 测试 安装插件 查询 小结 概述 REST作为一种现代网络应用非常流行的软件架构风格受到广大WEB开发者的喜爱,在目前软件架构设计模式中随处可见REST的身影,但是随着REST的流行与发展,它的一个最大的缺点开始暴露出来: 在很多时候客户端需要的数据往往在不同的地方具有相似性,但却又不尽相同. 如同样的用户信息,在有的场景下前端只需要用户的简要信息(

  • SpringBoot security安全认证登录的实现方法

    目录 前言 一.登录时序图 二.配置与代码 1.引入库 2.代码文件 参考文档 前言 本文章主要从spring security安全认证登录内部调用流程来流程分析登录过程. 一.登录时序图 时序原图 二.配置与代码 1.引入库 pom.xml: <!-- Spring框架基本的核心工具 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-contex

  • SpringBoot整合Swagger和Actuator的使用教程详解

    前言 本篇文章主要介绍的是SpringBoot整合Swagger(API文档生成框架)和SpringBoot整合Actuator(项目监控)使用教程. SpringBoot整合Swagger 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码. Swagger 介绍 Swagger 是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计.构建.记录以及使用 Rest API.Swagger 主要包含了以下三个部分: Swagger Editor:基于浏览器的编辑器,我们

  • SpringBoot Security整合JWT授权RestAPI的实现

    本教程主要详细讲解SpringBoot Security整合JWT授权RestAPI. 基础环境 技术 版本 Java 1.8+ SpringBoot 2.x.x Security 5.x JWT 0.9.0 创建项目 初始化项目 mvn archetype:generate -DgroupId=com.edurt.sli.slisj -DartifactId=spring-learn-integration-security-jwt -DarchetypeArtifactId=maven-ar

  • SpringBoot 签到奖励实现方案的示例代码

    前言 最近在做社交业务,用户进入APP后有签到功能,签到成功后获取相应的奖励: 项目状况:前期尝试业务阶段: 特点: 快速实现(不需要做太重,满足初期推广运营即可) 快速投入市场去运营 用户签到: 用户在每次启动时查询签到记录(规则:连续7日签到从0开始,签到过程中有断签从0开始) 如果今日未签到则提示用户可以进行签到 用户签到获取相应的奖励 提到签到,脑海中首先浮现特点: 需要记录每位用户每天的签到情况 查询时根据规则进行签到记录情况 需求&流程设计&技术实现方案 需求原型图 查询签到记

  • 在SpringBoot: SpringBoot里面创建导出Excel的接口教程

    在Web项目中,难免需要导出Excel这样的功能,后端接口怎么实现呢,Controller代码在下面,复制到项目的Controller中即可使用: 首先加入Excel的依赖,本例中我们用apache的poi: <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dep

随机推荐