Seguridad integrada SpringBoot (4) | (La seguridad se basa en JWT para lograr la separación del front-end y el inicio de sesión personalizado)

Seguridad integrada SpringBoot (4) | (La seguridad se basa en JWT para lograr la separación del front-end y el inicio de sesión personalizado)


Capítulo
Vínculo del capítulo 1: Seguridad integrada SpringBoot (1) | (Entrada de seguridad)
Vínculo del capítulo 2: Seguridad integrada SpringBoot (2) | (configuración personalizada de seguridad)
Vínculo del capítulo 3: Seguridad integrada SpringBoot (3) | (seguridad Front-end y back -fin de separación de inicio de sesión y procesamiento de respuesta)
Enlace del capítulo 4: seguridad integrada SpringBoot (4) | (La seguridad se basa en JWT para lograr la separación de front-end y el inicio de sesión personalizado)

prefacio

En el capítulo anterior, presentamos la configuración de usuarios basada en seguridad, la configuración de permisos y la configuración de recursos de Springboot. Y hemos reescrito el formulario de inicio de sesión para iniciar sesión, y el informe de errores de las excepciones de autenticación y autorización se ha tratado de manera uniforme, pero todavía hay algunos problemas. Todos los proyectos están separados de la parte delantera y trasera. En este capítulo, implementará el inicio de sesión de JWT en función de la separación de los extremos frontal y posterior.

Este artículo es una ampliación sobre la base del anterior, si no tienes muy clara la base del proyecto, por favor revisa el artículo anterior

1. Dependencias del proyecto

Incluye principalmente dependencias de seguridad y algunas dependencias de herramientas.

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.7</version>
        <relativePath/>
    </parent>
   <dependencies>
       <!--    springboot   start-->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <!--    springboot依赖    end-->

       <!--wagger2依赖start-->
       <dependency>
           <groupId>com.github.xiaoymin</groupId>
           <artifactId>knife4j-spring-ui</artifactId>
           <version>3.0.3</version>
       </dependency>
       <dependency>
           <groupId>io.springfox</groupId>
           <artifactId>springfox-swagger2</artifactId>
           <version>3.0.0</version>
       </dependency>

       <!--常用工具依赖start-->
       <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-lang3</artifactId>
           <version>3.12.0</version>
       </dependency>

       <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-collections4</artifactId>
           <version>4.1</version>
       </dependency>

       <dependency>
           <groupId>com.google.guava</groupId>
           <artifactId>guava</artifactId>
           <version>30.1.1-jre</version>
       </dependency>

       <!--fastjson引入-->
       <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>fastjson</artifactId>
           <version>1.2.49</version>
       </dependency>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>commons-codec</groupId>
           <artifactId>commons-codec</artifactId>
           <version>1.15</version>
       </dependency>

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

       <!--数据库引入引入-->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-jpa</artifactId>
       </dependency>
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <scope>runtime</scope>
       </dependency>
       <!--jwt引入-->
       <dependency>
           <groupId>io.jsonwebtoken</groupId>
           <artifactId>jjwt</artifactId>
           <version>0.9.1</version>
       </dependency>

       <dependency>
           <groupId>joda-time</groupId>
           <artifactId>joda-time</artifactId>
           <version>2.9.9</version>
       </dependency>
   </dependencies>
   

2. Procesamiento de respuestas personalizadas

El procesamiento de respuesta personalizado es principalmente para definir el formato de respuesta, lo cual es conveniente para la coordinación de front-end y back-end.

1. Defina el cuerpo de respuesta ResponseHandle

@Data
public class ResponseHandle<T> {
    
    
    private String status;
    private String desc;
    private T data;

    // 成功 无参构成函数
    public static ResponseHandle SUCCESS(){
    
    
        ResponseHandle result = new ResponseHandle();
        result.setDesc("成功");
        result.setResultCode(HttpCode.SUCCESS);
        return result;
    }
    //成功 有返回数据构造函数
    public static ResponseHandle SUCCESS(Object data){
    
    
        ResponseHandle result = new ResponseHandle();
        result.setData(data);
        result.setResultCode(HttpCode.SUCCESS);
        return result;
    }

    /**
     * 失败,指定status、desc
     */
    public static ResponseHandle FAIL(String status, String desc) {
    
    
        ResponseHandle result = new ResponseHandle();
        result.setStatus(status);
        result.setDesc(desc);
        return result;
    }

    /**
     * 失败,指定ResultCode枚举
     */
    public static ResponseHandle FAIL(HttpCode resultCode) {
    
    
        ResponseHandle result = new ResponseHandle();
        result.setResultCode(resultCode);
        return result;
    }
    /**
     * 把ResultCode枚举转换为ResResult
     */
    private void setResultCode(HttpCode code) {
    
    
        this.status = code.code();
        this.desc = code.message();
    }
}

2. Defina la enumeración de respuesta HttpCode

public enum HttpCode {
    
    

    // 成功状态码
    SUCCESS("00000", "成功"),
    UNKNOWN_ERROR("99999", "服务未知异常"),
    // 系统500错误
    SYSTEM_ERROR("10000", "系统异常,请稍后重试"),


    // 认证错误:20001-29999
    USER_NOAUTH("20000", "用户未登录"),
    TOKEN_ERROR("20001", "生成token失败"),
    LOGIN_ERROR("20002", "登录失败"),
    USER_LOCKED("20004", "账户已锁定"),
    USER_PASS_OUT("20005", "用户名或密码错误次数过多"),
    USER_NOTFIND_ERROR("20006", "没有找到用户"),
    USER_ERROR("20007", "用户名或密码不正确"),
    USER_CODE("20008", "验证码输入有误,请重新输入!"),
    USER_DISABLE("20009", "该账号也被禁用,请联系管理员!"),
    USER_INFOERROR("20010", "用户信息获取异常!"),
    USER_NOAUTHON("20011", "用户没有权限访问"),

    ;


    private String code;

    private String message;

    HttpCode(String code, String message) {
    
    
        this.code = code;
        this.message = message;
    }

    public String code() {
    
    
        return this.code;
    }

    public String message() {
    
    
        return this.message;
    }
}

Tres, clase de respuesta de inicio de sesión de usuario personalizado

Principalmente, cuando un usuario accede a los recursos, se verifica que el usuario no haya iniciado sesión y el formato de la información de front-end devuelta en el escenario donde el usuario ha iniciado sesión y no tiene derechos de acceso.

1. Indicar que el usuario no ha iniciado sesión

@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {
    
    
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
    
    
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        ResponseHandle fail = ResponseHandle.FAIL(HttpCode.USER_NOAUTHON);
        response.getWriter().write(JSONObject.toJSONString(fail));
    }
}

2. El usuario no tiene derechos de acceso al proceso

@Component
public class RestAuthorizationEntryPoint implements AuthenticationEntryPoint {
    
    

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
    
    
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        ResponseHandle fail = ResponseHandle.FAIL(HttpCode.USER_NOAUTH);
        response.getWriter().write(JSONObject.toJSONString(fail));
    }
}

Cuarto, implementación de inicio de sesión personalizado

1. Introducción a JwtAuthencationTokenFilter

El filtro BasicAuthenticationFilter tiene el mismo efecto que el filtro OncePerRequestFilter. Es un filtro de seguridad para implementar la autenticación de inicio de sesión del usuario. Cambie el filtro para que se active cuando el usuario visite. Podemos heredar esta clase y luego reescribir el método doFilterInternal para implementar interceptación de token, de modo que cada vez que la interfaz acceda al recurso, se recibirá el token para verificar si es válido y está caducado.

2. Realización de una interfaz personalizada de inicio de sesión con nombre de usuario y contraseña

Aquí, los usuarios pueden personalizar su propia lógica de implementación, como el cifrado de la contraseña del usuario, los parámetros de retorno, etc.

1. Interfaz de inicio de sesión

@Api(tags = {
    
    "登录相关接口"})
@RestController
@RequestMapping("/oak")
public class LoginCtrl {
    
    

    @Autowired
    private LoginService loginService;

    @ApiOperation(value = "用户登录接口", notes = "登录")
    @PostMapping("/login")
    public ResponseHandle login(@RequestBody User user, HttpServletRequest request) {
    
    
        return loginService.login(user, request);
    }
}

2. Inicie sesión para implementar el servidor

@Service
public class LoginServiceImpl implements LoginService {
    
    

    @Autowired
    private UserServiceImpl userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;


    @Override
    public ResponseHandle login(User user, HttpServletRequest request) {
    
    
        String username = user.getUsername();
        String password = user.getPassword();

//        String code = user.getCode();
//        // 验证码
//        String captcha = (String) request.getSession().getAttribute("captcha");
//        // 判断验证码
//        if ("".equals(code) || !captcha.equalsIgnoreCase(code)) {
    
    
//            return ResponseHandle.FAIL(HttpCode.USER_CODE);
//        }
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (userDetails.isEnabled()) {
    
    
            if (null == userDetails || !passwordEncoder.matches(password, userDetails.getPassword())) {
    
    
                return ResponseHandle.FAIL(HttpCode.USER_ERROR);
            }
            // 更新security登录用户对象
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
//            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //将authenticationToken放入spring security全局中
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            // 创建一个token
            String token = JwtTokenUtils.createToken(username, "", true);
            Map<String, String> tokenMap = new HashMap<>();
            tokenMap.put("token", "Bearer" + token);
            return ResponseHandle.SUCCESS(tokenMap);
        }
        return ResponseHandle.FAIL(HttpCode.USER_DISABLE);
    }
}

3. Consultar usuarios por nombre de usuario

@Service
public class UserServiceImpl implements UserDetailsService {
    
    

    @Autowired
    private UserRepository userRepository;

    /**
     *
     * @param s
     * @return 实现loadUserByUsername方法,根据用户名查找用户信息
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    
    
        User user = userRepository.findByUsername(s);
        return new JwtUser(user);
    }
}

4. JPA realiza la consulta de la base de datos del usuario

public interface UserRepository extends CrudRepository<User, Integer> {
    
    
    /**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    User findByUsername(String username);
}

5. Entidad usuaria

@Data
@Entity
@Table(name = "t_user")
public class User {
    
    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

    @Column(name = "username")
    private String username;

    @Column(name = "password")
    private String password;

    @Column(name = "code")
    private String code;

    @Column(name = "role")
    private String role;

    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", role='" + role + '\'' +
                '}';
    }
}

3. Configuración de seguridad

Configure la fuente de usuario de seguridad, el modo de autenticación, el filtro, etc. Aquí usamos nuestra propia interfaz de inicio de sesión, por lo que debemos dejarlo pasar y no usar el modo de envío de formulario.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    

    @Autowired
    private UserServiceImpl userService;

    @Resource
    private RestAuthorizationEntryPoint restAuthorizationEntryPoint;

    @Resource
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;



    /**
     * 常用的三种存储方式,项目找那个用的最多的为,自定义用户存储
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
    
        //1、内存用户配置
//        auth.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder())
//                .withUser("admin").password(bCryptPasswordEncoder().encode("123456")).authorities("ADMIN")
//                .and()
//                .withUser("test").password(bCryptPasswordEncoder().encode("123456")).authorities("TEST");
        //2、数据库用户配置
//        auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
//                .usersByUsernameQuery(
//                        "select username, password, status from Users where username = ?")
//                .authoritiesByUsernameQuery(
//                        "select username, authority from Authority where username = ?");
        //3、自定义用户存储
        auth.userDetailsService(userService)
                .passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * configure(WebSecurity)用于影响全局安全性(配置资源,设置调试模式,通过实现自定义防火墙定义拒绝请求)的配置设置。
     * 一般用于配置全局的某些通用事物,例如静态资源等
     *
     * @param web
     */
    @Override
    public void configure(WebSecurity web) {
    
    
        web.ignoring()
                .antMatchers(HttpMethod.OPTIONS, "/**")  ///跨域请求预处理
                .antMatchers("/favicon.ico")
                .antMatchers("/swagger**")   // 以下swagger静态资源、接口不拦截
                .antMatchers("/doc.html")
                .antMatchers("/swagger-resources/**")
                .antMatchers("/v2/api-docs")
                .antMatchers("/webjars/**")
//                .antMatchers("/logout")
                .antMatchers("/js/**", "/css/**", "/images/**");  // 排除html静态资源
    }

    /**
     * 配置接口拦截
     * configure(HttpSecurity)允许基于选择匹配在资源级配置基于网络的安全性,
     * 也就是对角色所能访问的接口做出限制
     *
     * @param httpSecurity 请求属性
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
    
    
        httpSecurity
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/demo/get").permitAll()
                .antMatchers("/oak/login", "/oak/logout").permitAll()
                //指定权限为ROLE_ADMIN才能访问,这里和方法注解配置效果一样,但是会覆盖注解
                .antMatchers("/demo/delete").hasRole("ADMIN")
                // 所有请求都需要验证
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthorizationEntryPoint)
                .and()
                .csrf().disable()
                .sessionManagement()//禁用session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .logout().logoutUrl("/logout")
                .and()
                // 禁用缓存
                .headers()
                .cacheControl();
    }


    /**
     * 配置用户认证方式
     *
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
    
    
        return super.authenticationManagerBean();
    }


    /**
     * 自定义过滤器,用来替换security的默认过滤器(UsernamePasswordAuthenticationFilter),
     * 实现自定义的login接口,接口路径为了区别默认的/login我们定义为/mylogin
     *
     * @return
     * @throws Exception
     */

    /**
     * 使用security 提供的加密规则(还有其他加密方式)
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
    
    
        return new BCryptPasswordEncoder();
    }

    /**
     * JWT token过滤器
     * @return
     * @throws Exception
     */
    @Bean
    public JwtAuthencationTokenFilter jwtAuthenticationFilter() throws Exception {
    
    
        JwtAuthencationTokenFilter jwtAuthenticationFilter = new JwtAuthencationTokenFilter(authenticationManager());
        return jwtAuthenticationFilter;
    }
}

4. Personaliza la implementación de JwtAuthencationTokenFilter

Configure las fuentes de seguridad de los usuarios, los modos de autenticación, los filtros, etc. Aquí definimos nuestra propia interfaz de inicio de sesión /mylogin

public class JwtAuthencationTokenFilter extends BasicAuthenticationFilter {
    
    
    private String tokenHeader = "Authorization";
    private String tokenHead = "Bearer";

    @Autowired
    private UserServiceImpl userService;

    public JwtAuthencationTokenFilter(AuthenticationManager authenticationManager) {
    
    
        super(authenticationManager);
    }

    /**
     * 自定义过滤器,用来校验token是否存在,token是否失效
     *
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
    
    
        // 请求头中获取token信息
        String authheader = request.getHeader(tokenHeader);
        // 存在token
        if (null != authheader && authheader.startsWith(tokenHead)) {
    
    
            // 去除字段名称, 获取真正token
            String authToken = authheader.substring(tokenHead.length());
            // 利用token获取用户名
            String username = JwtTokenUtils.getUsername(authToken);

            System.out.println("自定义JWT过滤器获得用户名为" + username);
            Authentication a = SecurityContextHolder.getContext().getAuthentication();

            // token存在用户未登陆
            // SecurityContextHolder.getContext().getAuthentication() 获取上下文对象中认证信息
            if (null != username && null == SecurityContextHolder.getContext().getAuthentication()) {
    
    
                // 自定义数据源获取用户信息
                UserDetails userDetails = userService.loadUserByUsername(username);
                // 验证token是否有效 验证token用户名和存储的用户名是否一致以及是否在有效期内, 重新设置用户对象
//                if (JwtTokenUtils.isExpiration(authToken)) {
    
    
                // 重新将用户信息封装到UsernamePasswordAuthenticationToken
                if (JwtTokenUtils.checkToken(authToken)) {
    
    
                    System.out.println("token有效");
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        //继续下一个拦截器
        filterChain.doFilter(request, response);
    }
}

4. Clase de herramienta JwtTokenUtils

Se utiliza principalmente para configurar y generar tokens, verificar tokens y otros métodos relacionados.

public class JwtTokenUtils {
    
    


    private static final String SECRET = "oak-secret";
    private static final String ISS = "oak";

    /**
     * 角色的key
     */
    private static final String ROLE_CLAIMS = "rol";

    /**
     * 过期时间是3600秒,既是1个小时
     */
    private static final long EXPIRATION = 3600L;

    /**
     * 选择了记住我之后的过期时间为7天
     */
    private static final long EXPIRATION_REMEMBER = 604800L;

    /**
     * 创建token
     *
     * @param username
     * @param role
     * @param isRememberMe
     * @return
     */
    public static String createToken(String username, String role, boolean isRememberMe) {
    
    
        long expiration = isRememberMe ? EXPIRATION_REMEMBER : EXPIRATION;
        HashMap<String, Object> map = new HashMap<>();
        map.put(ROLE_CLAIMS, role);
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .setClaims(map)  //存放自定义信息,也可不放
                .setIssuer(ISS)     //发行人
                .setSubject(username)   //jwt主题
                .setIssuedAt(new Date())   //当前时间
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)) // 过期时间
                .compact();
    }

    /**
     * 从token中获取用户名
     *
     * @param token
     * @return
     */
    public static String getUsername(String token) {
    
    
        return getTokenBody(token).getSubject();
    }


    /**
     * 获取用户角色
     *
     * @param token
     * @return
     */
    public static String getUserRole(String token) {
    
    
        return (String) getTokenBody(token).get(ROLE_CLAIMS);
    }

    /**
     * 是否已过期
     *
     * @param token
     * @return
     */
    public static boolean isExpiration(String token) {
    
    
        try {
    
    
            return getTokenBody(token).getExpiration().before(new Date());
        } catch (ExpiredJwtException e) {
    
    
            return true;
        }
    }


    /**
     * 根据token,判断token是否存在与有效
     *
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
    
    
        if (StringUtils.isEmpty(jwtToken)) return false;
        try {
    
    
            Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private static Claims getTokenBody(String token) {
    
    
        return Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(token)
                .getBody();
    }
}

4. Verificar inicio de sesión

1. Escriba la interfaz de prueba

@Api(tags = {
    
    "演示相关接口"})
@RestController
@RequestMapping("/demo")
public class DemoCtrl {
    
    

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;


    @ApiOperation(value = "获取接口", notes = "获取接口")
    @GetMapping(value = "/get")
    public ResponseHandle get() {
    
    
        return ResponseHandle.SUCCESS("获取数据成功");
    }

    @ApiOperation(value = "更新接口(ADMIN可访问)", notes = "更新接口")
    @GetMapping(value = "/update1")
    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    public ResponseHandle update1() {
    
    
        return ResponseHandle.SUCCESS("更新数据成功");
    }

    @ApiOperation(value = "查询接口(USER可访问)", notes = "查询接口")
    @GetMapping(value = "/find")
    @PreAuthorize("hasAnyRole('ROLE_USER')")
    public ResponseHandle find() {
    
    
        return ResponseHandle.SUCCESS("查询数据成功");
    }

    @ApiOperation(value = "删除用户(ADMIN配置可用)", notes = "修改")
    @GetMapping("/delete")
    public ResponseHandle delete() {
    
    
        return ResponseHandle.SUCCESS("删除成功");
    }

    @ApiOperation(value = "注册用户", notes = "注册")
    @PostMapping("/register")
    public String registerUser(@RequestBody Map<String, String> registerUser) {
    
    
        User user = new User();
        user.setUsername(registerUser.get("username"));
        user.setPassword(bCryptPasswordEncoder.encode(registerUser.get("password")));
        user.setRole("ROLE_USER");
        User save = userRepository.save(user);
        return save.toString();
    }
}

2. Indicador de interfaz de llamada

1. Llame a la interfaz de llamada de inicio de sesión.
Por favor agregue una descripción de la imagen
Puede ver que la interfaz devuelve una larga cadena de tokens. La próxima vez que accedamos a los recursos del servicio, solo necesitamos traer el token modificado.

2. Llame a la interfaz de eliminación
Por favor agregue una descripción de la imagen> 3. Cambie a un usuario cuyo rol sea USUARIO para llamar a la interfaz de eliminaciónPor favor agregue una descripción de la imagen

Resumir

En este punto, springboot integra la seguridad para completar la configuración de la base de datos del usuario y el inicio de sesión personalizado, y mejora las respuestas relacionadas con el inicio de sesión, lo que facilita el procesamiento unificado de los extremos frontal y posterior. Este tipo de inicio de sesión puede satisfacer las necesidades de un solo proyecto, pero teniendo en cuenta la autenticación de inicio de sesión entre varios proyectos, todavía hay muchos problemas en esta solución. A continuación, continuaremos completando el método de autenticación basado en el token OAuth2.

Enlaces al Capítulo 1: SpringBoot Integrated Security (1) | (Introducción a la seguridad)
Enlaces al Capítulo 2: SpringBoot Integrated Security (2) | (Configuración personalizada de seguridad)
Enlaces al Capítulo 3: SpringBoot Integrated Security (3) | (Antes y después Seguridad Procesamiento de respuestas e inicio de sesión separados por extremos)
Enlace del capítulo 4: Seguridad integrada de SpringBoot (4) | (La seguridad se basa en JWT para lograr la separación de front-end y el inicio de sesión personalizado)

Supongo que te gusta

Origin blog.csdn.net/Oaklkm/article/details/128190531
Recomendado
Clasificación