新手小白入门Spring Security

一、概述

Spring Security 是一个企业级安全框架,由spring官方推出,它对软件系统中的认证,授权,加密等功能进行封装,并在springboot技术推出以后,配置方面做了很大的简化

二、基本架构

Spring Security 在企业中实现认证和授权业务时,底层构建了大量的过滤器
在这里插入图片描述
其中:
绿色部分为认证过滤器,需要我们自己配置,也可以配置多个认证过滤器.也可以使用Spring Security提供的默认认证过滤器.黄色部分为授权过滤器.Spring Security就是通过这些过滤器然后调用相关对象一起完成认证和授权操作.

三、调用流程

在这里插入图片描述
在过滤器中依据用户名和密码构建了一个UsernamePasswordAuthenticationToken(Authentication的一个实现)对象,其实就是一个Authentication的实现,他封装了我们需要的认证信息。之后会调用AuthenticationManager.。这个类其实并不会去验证我们的信息,信息验证的逻辑都是在AuthenticationProvider里面,而Manager的作用则是去管理Provider,管理的方式是通过for循环去遍历(因为不同的登录逻辑是不一样的,比如表单登录、第三方登录。
AuthenticationProvider去调用UserDetailsService拿到用户信息,然后做一些检查。最后把用户信息拼装到一个已经认证了的Authentication里面

四、入门案例

创建springboot工程,添加springboot基础相关依赖,这里不介绍啦
pom文件添加spring security相关依赖

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

启动后控制台生成一个密码
在这里插入图片描述
浏览器访问 http://localhost:8080/login
在这里插入图片描述
用户名 :user(系统默认),密码:服务启动时,控制台默认输出的密码:,点击Sign in进行登录,登录成功默认会出现,如下界面:
在这里插入图片描述
自定义登录成功页面
在项目的resources目录下创建static目录,并在此目录创建一个index.html文件,
在这里插入图片描述
启动服务,再次进行登录访问测试,登录成功以后系统默认会跳转到index.html页面,例如
在这里插入图片描述
application.yml文件配置登录用户名和密码

spring:
  security:
    user:
      name: jack
      password: 123456

重启项目,访问登录页面 用户名/密码分别为上面yml文件配置的 jack/123456
但上面配置过于简单,我们需要对密码进行加密处理
编写测试类

    public static void main(String[] args) {
        BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
        String password="123456";//明文
        String newPwd=encoder.encode(password);
        System.out.println(newPwd);//$2a$10$rl86aosqAfoLcmuEo9TfCO4QE532UmDeeVrd0.lflKwfvRkKd/.gi
    }

application.yml 配置加密的密码以及加密算法

spring:
  security:
    user:
      name: jack #这种写法,密码太简单了
      #{bcrypt}指定了密码加密时使用的算法
      password: '{bcrypt}$2a$10$rl86aosqAfoLcmuEo9TfCO4QE532UmDeeVrd0.lflKwfvRkKd/.gi'

说明:Bcrypt,底层基于随机盐方式对密码进行hash不可逆加密,更加安全,缺陷是慢

重启服务器,访问登录页面,用户名/密码: jack/123456

五、SpringSecurity认证逻辑实现

SpringSecurity支持通过配置文件的方式定义用户信息(账号密码和角色等),但这种方式有明显的缺点,那就是系统上线后,用户信息的变更比较麻烦。因此SpringSecurity还支持通过实现UserDetailsService接口的方式来提供用户认证授权信息,其应用过程如下:

1 数据库表设计

在这里插入图片描述
数据库查询用户权限sql基础示例

SELECT GROUP_CONCAT(t.permission) from (
  SELECT DISTINCT m.permission from sys_user u  
          LEFT JOIN sys_user_role ur on u.id= ur.user_id 
          LEFT JOIN  sys_role_menu rm  on ur.role_id=rm.role_id
          LEFT JOIN  sys_menu m  on rm.menu_id=m.id WHERE u.id=1
)t

2 自定义登录逻辑

定义UserDetailService接口实现类,自定义登陆逻辑,UserDetailService为SpringSecurity官方提供的登录逻辑处理对象,我们自己可以实现此接口,然后在对应的方法中进行登录逻辑的编写即可.

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysAuthorityMapper sysAuthorityMapper;

    /**
     * 当我们执行登录操作时,底层会通过过滤器等对象调用这个方法
     * @param username 这个参数为登录页面输入的用户名
     * @return 从数据库基于用户名查询到的用户信息
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名从数据库查询到用户的信息,包含用户名,密码等
        SysUser sysUser = sysUserMapper.selectOne(new QueryWrapper<>(new SysUser().setUsername(username)));
        //假如分配权限的方式是角色,编写字符串时用"ROLE_"做前缀,示例"ROLE_admin,ROLE_normal,sys:res:retrieve,sys:res:create"
        String dataAuthorities = sysAuthorityMapper.selectGrantedAuthorities(sysUser.getId());
        List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(dataAuthorities);
        //这个user是SpringSecurity提供的UserDetails接口的实现,用于封装用户信息
        // 后续我们也可以基于需要自己构建UserDetails接口的实现
        return new User(username, sysUser.getPassword(), grantedAuthorities);
    }

说明,这里的User对象会交给SpringSecurity框架,框架提取出密码信息,然后与用户输入的密码进行匹配校验.
启动服务进行登陆,访问测试。

3 自定义登陆页面

在resources目录下static目录下新建login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Please sign in</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <form class="form-signin" method="post" action="/login">
        <h2 class="form-signin-heading">Please sign in</h2>
        <p>
            <label for="username" class="sr-only">Username</label>
            <input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>
        </p>
        <p>
            <label for="password" class="sr-only">Password</label>
            <input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
        </p>
        <input name="_csrf" type="hidden" value="cc1471a5-3246-43ff-bef7-31d714273899" />
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    </form>
</div>
</body>
</html>

注意:请求的url暂时为”/login”,请求方式必须为post方式,请求的参数暂时必须为username,password。这些规则默认在UsernamePasswordAuthenticationFilter中进行了定义。

添加安全配置类SpringSecurityConfig,让其实现接口,并重写相关config方法,进行登陆设计,代码如下:

/**
 * 由@Configuration注解描述的类为spring中的配置类,配置类会在spring启动时优先加载,在配置类中通常会对第三方资源进行配置
 */
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 对http请求的安全控制进行配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();//关闭跨域攻击

        //自定义登陆表单
        http.formLogin()
                .loginPage("/login.html")//设置登录页面
                .loginProcessingUrl("/login")//设置登陆请求处理地址(对应form表单中的action),登陆时会访问UserDetailService对象
                .usernameParameter("username")//设置请求用户名参数为username(默认就是username,可以自己修改,需要与表单同步)
                .passwordParameter("password") //请求密码参数为password(默认就是password,可以自己修改,需要与表单同步)
                //.successForwardUrl("/index");//请求转发controller中的一个方法
                .defaultSuccessUrl("/index.html")//设置登录成功跳转页面
                .failureUrl("/login.html?error")//登陆失败访问的页面(默认为/login.html?error)

        ;

        //设计登出信息
        http.logout()
                .logoutUrl("/logout")   //登出路径
                .logoutSuccessUrl("/login.html?logout");//设置登出后显示的页面

        //认证设计
        http.authorizeRequests()
                //设置要放行的资源
                //“*”用于匹配0个或多个字符   “**”用于匹配0个或多个目录及字符
                .antMatchers("/login.html", "/images/**").permitAll() //设置上述所有路径不需要登录就能访问(放行)
                //设置需要认证的请求(除了上面的要放行,其它都要进行认证)
                .anyRequest().authenticated()
        ;
    }

    /**
     * 定义密码加密对象
     *
     * @Bean注解通常会在@Configuration注解描述的类中描述方法,用于告诉spring框架这个方法的返回值会交给spring管理 并且spring管理的对象起个默认的名字,这个名字与方法名相同,当然也可以通过@Bean注解起名字
     */
    @Bean//对象名默认会方法名passwordEncoder
    //@Bean("bCryptPasswordEncoder") 对象名为bCryptPasswordEncoder
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

4 登陆成功和失败处理器

现在的很多系统都采用的是前后端分离设计,我们登陆成功以后可能会跳转到前端系统的某个地址,或者返回一个json数据,我们可以自己定义登录成功的处理操作

4.1 成功执行重定向的处理器

SpringSecurityConfig 类添加登录成功可以直接执行重定向的处理器代码

 /**
     * 登录成功可以直接执行重定向的处理器
     * @param redirectUrl 登录成功要跳转的url
     */
    public AuthenticationSuccessHandler redirectAuthenticationSuccessHandler(String redirectUrl) {
        return (req, res, authentication) -> res.sendRedirect(redirectUrl);
    }

4.2 成功返回JSON数据的处理器

编写工具类,定义统一返回数据格式

public class WebUtils {

    /**
     * 将数据以json格式写到客户端
     * @param response 响应对象,负责向客户端输出数据的对象
     */
    public static void writeJsonToClient(HttpServletResponse response,String[] key,Object[] value) throws IOException {
        //1、设置响应数据的编码
        response.setCharacterEncoding("utf-8");
        //2.告诉浏览器响应数据的内容类型以及编码
        response.setContentType("application/json;charset=utf-8");
        //3.将数据转换为json格式字符串
        String jsonStr = new ObjectMapper().writeValueAsString(getDataMap(key,value));
        //4.获取输出流对象将json数据写到客户端
        //4.1获取输出流对象
        PrintWriter out = response.getWriter();
        //4.2通过输出流向网络客户端写数据
        out.println(jsonStr);
        out.flush();
        out.close();
    }

    /**
     * 根据传入的key,value封装map数据
     */
    public static Map<String,Object> getDataMap(String[] key,Object[] value){
        Map<String,Object> map =new HashMap<>();
        for(int i=0;i<key.length;i++){
            map.put(key[i],value[i]);
        }
        return map;
    }
}

SpringSecurityConfig 类添加登录成功直接返回JSON数据的处理器代码

    /**
     * 登录成功直接返回JSON数据的处理器
     */
    public AuthenticationSuccessHandler jsonAuthenticationSuccessHandler() {
        return (req, res, authentication) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_OK, "login ok"});
    }

4.3 失败重定向到页面的处理器

SpringSecurityConfig 类添加登陆失败重定向到页面的处理器代码

   /**
     * 登陆失败重定向到页面
     */
    public AuthenticationFailureHandler redirectAuthenticationFailureHandler(String redirectUrl) {
        return (req, res, authenticationException) -> res.sendRedirect(redirectUrl);
    }

4.4 失败返回json数据的处理器

SpringSecurityConfig 类添加登陆失败返回json数据的处理器代码

    /**
     * 登录失败返回json数据
     */
    public AuthenticationFailureHandler jsonAuthenticationFailureHandler() {
        return (req, res, authentication) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "username or password error"});
    }

5 设置登录成功失败处理器

SpringSecurityConfig类中configure方法添加成功失败处理器代码
在这里插入图片描述
SpringSecurityConfig类总代码

package com.zhanlijuan.config;

import com.zhanlijuan.util.WebUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.http.HttpServletResponse;

/**
 * 由@Configuration注解描述的类为spring中的配置类,配置类会在spring启动时优先加载,在配置类中通常会对第三方资源进行配置
 */
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 对http请求的安全控制进行配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();//关闭跨域攻击

        //自定义登陆表单
        http.formLogin()
                .loginPage("/login.html")//设置登录页面
                .loginProcessingUrl("/login")//设置登陆请求处理地址(对应form表单中的action),登陆时会访问UserDetailService对象
                .usernameParameter("username")//设置请求用户名参数为username(默认就是username,可以自己修改,需要与表单同步)
                .passwordParameter("password") //请求密码参数为password(默认就是password,可以自己修改,需要与表单同步)
                //.successForwardUrl("/index");//请求转发controller中的一个方法
                .defaultSuccessUrl("/index.html")//设置登录成功跳转页面
                .failureUrl("/login.html?error")//登陆失败访问的页面(默认为/login.html?error)
                //.successHandler(redirectAuthenticationSuccessHandler("https://www.baidu.com")) 登录成功重定向到https://www.baidu.com"
                .successHandler(jsonAuthenticationSuccessHandler())//登录成功返回json数据
                //.failureHandler(redirectAuthenticationFailureHandler("https://www.jd.com/"))//登录失败跳转到https://www.jd.com/
                .failureHandler(jsonAuthenticationFailureHandler())//失败返回json数据

        ;

        //设计登出信息
        http.logout()
                .logoutUrl("/logout")   //登出路径
                .logoutSuccessUrl("/login.html?logout");//设置登出后显示的页面

        //认证设计
        http.authorizeRequests()
                //设置要放行的资源
                //“*”用于匹配0个或多个字符   “**”用于匹配0个或多个目录及字符
                .antMatchers("/login.html", "/images/**").permitAll() //设置上述所有路径不需要登录就能访问(放行)
                //设置需要认证的请求(除了上面的要放行,其它都要进行认证)
                .anyRequest().authenticated()
        ;
    }

    /**
     * 登录成功可以直接执行重定向的处理器
     *
     * @param redirectUrl 登录成功要跳转的url
     */
    public AuthenticationSuccessHandler redirectAuthenticationSuccessHandler(String redirectUrl) {
        return (req, res, authentication) -> res.sendRedirect(redirectUrl);
    }

    /**
     * 登录成功直接返回JSON数据的处理器
     */
    public AuthenticationSuccessHandler jsonAuthenticationSuccessHandler() {
        return (req, res, authentication) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_OK, "login ok"});
    }


    /**
     * 登陆失败重定向到页面
     */
    public AuthenticationFailureHandler redirectAuthenticationFailureHandler(String redirectUrl) {
        return (req, res, authenticationException) -> res.sendRedirect(redirectUrl);
    }

    /**
     * 登录失败返回json数据
     */
    public AuthenticationFailureHandler jsonAuthenticationFailureHandler() {
        return (req, res, authentication) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "username or password error"});
    }

    /**
     * 定义SpringSecurity密码加密对象
     *
     * @Bean注解通常会在@Configuration注解描述的类中描述方法,用于告诉spring框架这个方法的返回值会交给spring管理 并且spring管理的对象起个默认的名字,这个名字与方法名相同,当然也可以通过@Bean注解起名字
     */
    @Bean//对象名默认会方法名passwordEncoder
    //@Bean("bCryptPasswordEncoder") 对象名为bCryptPasswordEncoder
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

启动服务进行访问测试(分别用正确和错误的账号进行测试)。

六、SpringSecurity授权逻辑实现

1 添加启用全局方法访问控制注解

SpringSecurityConfig 配置类添加全局方法访问控制注解

@EnableGlobalMethodSecurity(prePostEnabled = true)

说明:注解由SpringSecurity提供,用于描述权限配置类,告诉系统底层在启动时,进行访问权限的初始化配置其中prePostEnabled= true表示启动权限管理功能
在这里插入图片描述

2 定义资源Controller

定义一个ResourceController类,作为资源访问对象,

@RestController
public class ResourceController {

    @PreAuthorize("hasAuthority('sys:user:update')")
    @GetMapping("/doCreate")
    public String doCreate(){
        return "create resource ok";
    }

    @PreAuthorize("hasAuthority('sys:user:delete')")
    @GetMapping("/doDelete")
    public String doDelete(){
        return "delete resource ok";
    }
}

其中,@PreAuthorize注解描述方法时,用于告诉系统访问此方法时需要进行权限检测。需要具备指定权限才可以访问。例如:
@PreAuthorize(“hasAuthority('sys:user:delete”) 需要具备sys:user:delete权限
@PreAuthorize(“hasRole(‘admin’)”) 需要具备admin角色
使用不同用户进行登陆,然后执行资源访问,假如没有权限,则会看到响应状态吗403,如图所示:
在这里插入图片描述

七、SpringSecurity认证和授权异常处理

1 异常类型

对于SpringSecurity框架而言,在实现认证和授权业务时,可能出现如下两大类型异常:

  • AuthenticationException 用户还没有认证就去访问某个需要认证才可访问的方法时,可能出现的异常,这个异常通常对应的状态码401
  • AccessDeniedException 用户认证以后,在访问一些没有权限的资源时,可能会出现的异常,这个异常通常对应的状态吗为403

2 异常处理规范

SpringSecurity框架给了默认的异常处理方式,当默认的异常处理方式不满足我们实际业务需求时,此时我们就要自己定义异常处理逻辑,编写逻辑时需要遵循如下规范:
1)AuthenticationEntryPoint:统一处理 AuthenticationException 异常
2)AccessDeniedHandler:统一处理 AccessDeniedException 异常.

3 自定义异常处理逻辑

3.1 处理没有认证的访问异常

SpringSecurityConfig 添加代码

    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (req, res, authenticationException) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_UNAUTHORIZED, "请先登录"});
    }

3.2 处理没有权限时抛出的异常

SpringSecurityConfig 添加代码

    public AccessDeniedHandler accessDeniedHandler(){
       return (req,  res, accessDeniedException ) -> WebUtils.writeJsonToClient(res, new String[]{"state","msg"}, new Object[]{HttpServletResponse.SC_FORBIDDEN,"没有访问权限,请联系管理员"});
    }

3.3 配置异常处理对象

在配置类SecurityConfig中添加自定义异常处理对象,代码如下

        //需要认证与拒绝访问的异常处理器
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint())//没有认证时执行
                .accessDeniedHandler(accessDeniedHandler());//没有授权是执行DefaultAccessDeniedExceptionHandler

SecurityConfig类全部代码

/**
 * 由@Configuration注解描述的类为spring中的配置类,配置类会在spring启动时优先加载,在配置类中通常会对第三方资源进行配置
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 对http请求的安全控制进行配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();//关闭跨域攻击

        //自定义登陆表单
        http.formLogin()
                .loginPage("/login.html")//设置登录页面
                .loginProcessingUrl("/login")//设置登陆请求处理地址(对应form表单中的action),登陆时会访问UserDetailService对象
                .usernameParameter("username")//设置请求用户名参数为username(默认就是username,可以自己修改,需要与表单同步)
                .passwordParameter("password") //请求密码参数为password(默认就是password,可以自己修改,需要与表单同步)
                //.successForwardUrl("/index");//请求转发controller中的一个方法
                .defaultSuccessUrl("/index.html")//设置登录成功跳转页面
                .failureUrl("/login.html?error")//登陆失败访问的页面(默认为/login.html?error)
                //.successHandler(redirectAuthenticationSuccessHandler("https://www.baidu.com")) 登录成功重定向到https://www.baidu.com"
                .successHandler(jsonAuthenticationSuccessHandler())//登录成功返回json数据
                //.failureHandler(redirectAuthenticationFailureHandler("https://www.jd.com/"))//登录失败跳转到https://www.jd.com/
                .failureHandler(jsonAuthenticationFailureHandler())//失败返回json数据

        ;

        //需要认证与拒绝访问的异常处理器
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint())//没有认证时执行
                .accessDeniedHandler(accessDeniedHandler());//没有授权是执行DefaultAccessDeniedExceptionHandler

        //设计登出信息
        http.logout()
                .logoutUrl("/logout")   //登出路径
                .logoutSuccessUrl("/login.html?logout");//设置登出后显示的页面

        //认证设计
        http.authorizeRequests()
                //设置要放行的资源
                //“*”用于匹配0个或多个字符   “**”用于匹配0个或多个目录及字符
                .antMatchers("/login.html", "/images/**").permitAll() //设置上述所有路径不需要登录就能访问(放行)
                //设置需要认证的请求(除了上面的要放行,其它都要进行认证)
                .anyRequest().authenticated()
        ;
    }

    /**
     * 没有认证的访问异常逻辑
     */
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (req, res, authenticationException) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_UNAUTHORIZED, "请先登录"});
    }

    /**
     * 处理没有权限时抛出的异常
     */
    public AccessDeniedHandler accessDeniedHandler() {
        return (req, res, accessDeniedException) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_FORBIDDEN, "没有访问权限,请联系管理员"});
    }

    /**
     * 登录成功可以直接执行重定向的处理器
     *
     * @param redirectUrl 登录成功要跳转的url
     */
    public AuthenticationSuccessHandler redirectAuthenticationSuccessHandler(String redirectUrl) {
        return (req, res, authentication) -> res.sendRedirect(redirectUrl);
    }

    /**
     * 登录成功直接返回JSON数据的处理器
     */
    public AuthenticationSuccessHandler jsonAuthenticationSuccessHandler() {
        return (req, res, authentication) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_OK, "login ok"});
    }


    /**
     * 登陆失败重定向到页面
     */
    public AuthenticationFailureHandler redirectAuthenticationFailureHandler(String redirectUrl) {
        return (req, res, authenticationException) -> res.sendRedirect(redirectUrl);
    }

    /**
     * 登录失败返回json数据
     */
    public AuthenticationFailureHandler jsonAuthenticationFailureHandler() {
        return (req, res, authentication) -> WebUtils.writeJsonToClient(res, new String[]{"state", "msg"}, new Object[]{HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "username or password error"});
    }

    /**
     * 定义SpringSecurity密码加密对象
     *
     * @Bean注解通常会在@Configuration注解描述的类中描述方法,用于告诉spring框架这个方法的返回值会交给spring管理 并且spring管理的对象起个默认的名字,这个名字与方法名相同,当然也可以通过@Bean注解起名字
     */
    @Bean//对象名默认会方法名passwordEncoder
    //@Bean("bCryptPasswordEncoder") 对象名为bCryptPasswordEncoder
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

配置完成后,重启服务,测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值