Sécurité intégrée SpringBoot (4) | (La sécurité est basée sur JWT pour obtenir une séparation frontale et une connexion personnalisée)

Sécurité intégrée SpringBoot (4) | (La sécurité est basée sur JWT pour obtenir une séparation frontale et une connexion personnalisée)


Chapitre
Lien chapitre 1 : Sécurité intégrée SpringBoot (1) | (entrée de sécurité)
Lien chapitre 2 : Sécurité intégrée SpringBoot (2) | (configuration personnalisée de la sécurité)
Lien chapitre 3 : Sécurité intégrée SpringBoot (3) | (sécurité Front-end et back -end separation login and response processing)
Lien vers le chapitre 4 : Sécurité intégrée SpringBoot (4) | (La sécurité est basée sur JWT pour obtenir une séparation frontale et une connexion personnalisée)

avant-propos

Dans le chapitre précédent, nous avons présenté la configuration utilisateur basée sur la sécurité de springboot, la configuration des autorisations et la configuration des ressources. Et nous avons réécrit le formulaire de connexion pour se connecter, et le rapport d'erreur des exceptions d'authentification et d'autorisation a été traité de manière uniforme, mais il reste encore quelques problèmes. Les projets sont tous séparés du front et du back-end. Dans ce chapitre, nous mettra en œuvre la connexion JWT basée sur la séparation des extrémités avant et arrière.

Cet article est une extension sur la base du précédent. Si vous n'êtes pas très clair sur la base du projet, veuillez consulter l'article précédent

1. Dépendances du projet

Il comprend principalement des dépendances de sécurité et certaines dépendances d'outils

    <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. Traitement personnalisé des réponses

Le traitement des réponses personnalisées consiste principalement à définir le format de réponse, ce qui est pratique pour la coordination frontale et dorsale

1. Définir le corps de la réponse 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. Définir l'énumération de réponse 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;
    }
}

Trois, classe de réponse de connexion utilisateur personnalisée

Principalement lorsqu'un utilisateur accède aux ressources, il est vérifié que l'utilisateur n'est pas connecté et le format des informations frontales renvoyées dans le scénario où l'utilisateur est connecté et n'a pas de droits d'accès

1. Invite que l'utilisateur n'est pas connecté

@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. L'utilisateur n'a pas les droits d'accès pour traiter

@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));
    }
}

Quatrièmement, implémentation de connexion personnalisée

1. Introduction à JwtAuthencationTokenFilter

Le filtre BasicAuthenticationFilter a le même effet que le filtre OncePerRequestFilter. Il s'agit d'un filtre de sécurité pour implémenter l'authentification de connexion de l'utilisateur. Modifiez le filtre pour le recevoir lorsque l'utilisateur y accède. Nous pouvons hériter de cette classe, puis réécrire la méthode doFilterInternal pour l'implémenter interception de jeton personnalisé , de sorte que chaque fois que l'interface accède à la ressource, le jeton sera reçu pour vérifier s'il est valide et expiré.

2. Réalisation d'une interface de connexion personnalisée avec nom d'utilisateur et mot de passe

Ici, les utilisateurs peuvent personnaliser leur propre logique d'implémentation, telle que le cryptage du mot de passe utilisateur, les paramètres de retour, etc.

1. Interface de connexion

@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. Connectez-vous pour implémenter le serveur

@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. Interroger les utilisateurs par nom d'utilisateur

@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 réalise l'utilisateur de requête de base de données

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

5. Entité utilisatrice

@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. Configuration de la sécurité

Configurez la source d'utilisateurs de sécurité, le mode d'authentification, le filtre, etc. Ici, nous utilisons notre propre interface de connexion, nous devons donc la laisser aller et ne pas utiliser le mode de soumission de formulaire

@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. Personnalisez l'implémentation de JwtAuthencationTokenFilter

Configurez les sources d'utilisateurs de sécurité, les modes d'authentification, les filtres, etc. Ici, nous définissons notre propre interface de connexion / 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. Classe d'outils JwtTokenUtils

Il est principalement utilisé pour configurer et générer des jetons, vérifier des jetons et d'autres méthodes connexes

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. Vérifiez la connexion

1. Ecrire l'interface de test

@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. Invite d'interface d'appel

1. Appelez l'interface d'appel de connexion.
Veuillez ajouter une description de l'image
Vous pouvez voir que l'interface renvoie une longue chaîne de jetons. La prochaine fois que nous accéderons aux ressources de service, nous n'aurons qu'à apporter le jeton modifié.

2. Appelez l'interface de suppression
Veuillez ajouter une description de l'image> 3. Changez pour un utilisateur dont le rôle est USER pour appeler l'interface de suppressionVeuillez ajouter une description de l'image

Résumer

À ce stade, springboot intègre la sécurité pour compléter la configuration de la base de données de l'utilisateur et la connexion personnalisée, et améliore les réponses liées à la connexion, ce qui facilite le traitement unifié des front-end et back-ends. Ce type de connexion peut répondre aux besoins d'un seul projet, mais compte tenu de l'authentification de connexion entre plusieurs projets, cette solution pose encore de nombreux problèmes. Ensuite, nous continuerons à compléter la méthode d'authentification basée sur le jeton OAuth2.

Liens vers le chapitre 1 : SpringBoot Integrated Security (1) | (Introduction à la sécurité)
Liens vers le chapitre 2 : SpringBoot Integrated Security (2) | (Configuration personnalisée de la sécurité)
Liens vers le chapitre 3 : SpringBoot Integrated Security (3) | (Avant et après Sécurité Connexion et traitement des réponses séparés par des extrémités)
Lien du chapitre 4 : Sécurité intégrée SpringBoot (4) | (La sécurité est basée sur JWT pour obtenir une séparation frontale et une connexion personnalisée)

Je suppose que tu aimes

Origine blog.csdn.net/Oaklkm/article/details/128190531
conseillé
Classement