• springboot项目整理(持续更新)


    SpringSecurity

    1.导入依赖:

    在pom.xml中导入依赖,再访问页面就会出现login,这是SpringSecurity自己写的页面,用于登录认证

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>2.7.3</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.配置类:

    使用SecurityConfig继承WebSecurityConfigurerAdapter,用于自定义 security 策略

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter
    
    • 1
    • 2
    • 3

    需添加@EnableWebSecurity注解,有两个作用:
    a.加载了WebSecurityConfiguration配置类, 配置安全认证策略。
    b. 加载了AuthenticationConfiguration, 配置了认证信息。
    具体参照:@EnableWebSecurity注解

    SecurityConfig代码如下:

    package com.kob.backend.config;
    
    import com.kob.backend.config.filter.JwtAuthenticationTokenFilter;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    	//过滤器
        @Autowired
        private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    
    	//注册PasswordEncoder,使用BCryptPasswordEncoder进行加密
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    	
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
            		 // 所有的rest服务一定要设置为无状态,以提升操作效率和性能
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    //看成是不同配置之间的分隔
                    .and()
                    .authorizeRequests()
                    //设置可以访问的url
                    .antMatchers("/user/account/token/", "/user/account/register/").permitAll()
                    
                    .antMatchers(HttpMethod.OPTIONS).permitAll()
                    //对http所有的请求必须通过授权认证才可以访问
                    .anyRequest().authenticated();
    
    		//设置过滤器
            http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在这里插入图片描述

    3.JwtAuthenticationTokenFilter:

    a.OncePerRequestFilter是Spring Boot里面的一个过滤器抽象类,其同样在Spring Security里面被广泛用到,这个过滤器抽象类通常被用于继承实现并在每次请求时只执行一次过滤

    package com.kob.backend.config.filter;
    
    import com.kob.backend.mapper.UserMapper;
    import com.kob.backend.pojo.User;
    import com.kob.backend.service.impl.utils.UserDetailsImpl;
    import com.kob.backend.utils.JwtUtil;
    import io.jsonwebtoken.Claims;
    import org.jetbrains.annotations.NotNull;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @Component
    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
        @Autowired
        private UserMapper userMapper;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
            String token = request.getHeader("Authorization");
    
            if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
                filterChain.doFilter(request, response);
                return;
            }
    
            token = token.substring(7);
    
            String userid;
            try {
                Claims claims = JwtUtil.parseJWT(token);
                userid = claims.getSubject();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    
            User user = userMapper.selectById(Integer.parseInt(userid));
    
            if (user == null) {
                throw new RuntimeException("用户名未登录");
            }
    
            UserDetailsImpl loginUser = new UserDetailsImpl(user);
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginUser, null, null);
    
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    
            filterChain.doFilter(request, response);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    User相关代码

    1.InfoController调用InfoService得到用户消息

    InfoController代码:

    package com.kob.backend.controller.user.account;
    
    
    import com.kob.backend.service.user.account.InfoService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Map;
    
    @RestController
    public class InfoController {
    
        @Autowired
        private InfoService infoService;
    
        @GetMapping("/user/account/info/")
        public Map<String, String> getinfo(){
            return infoService.getInfo();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    InfoServiceImpl实现InfoService服务:

    package com.kob.backend.service.impl.user.account;
    
    import com.kob.backend.pojo.User;
    import com.kob.backend.service.impl.utils.UserDetailsImpl;
    import com.kob.backend.service.user.account.InfoService;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class InfoServiceImpl implements InfoService {
        @Override
        public Map<String, String> getInfo() {
            UsernamePasswordAuthenticationToken authentication =
                    (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
            //通过Authentication.getPrincipal()可以获取到代表当前用户的信息,这个对象通常是UserDetails的实例
            UserDetailsImpl loginUser = (UserDetailsImpl) authentication.getPrincipal();
            User user = loginUser.getUser();
    
            Map<String, String> map = new HashMap<>();
            map.put("error_message", "success");
            map.put("id", user.getId().toString());
            map.put("username", user.getUsername());
            map.put("photo", user.getPhoto());
            return map;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    UserDetailsImpl实现UserDetails

    package com.kob.backend.service.impl.utils;
    
    import com.kob.backend.pojo.User;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import java.util.Collection;
    
    /*
    @Data : 注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法
    @AllArgsConstructor : 注在类上,提供类的全参构造
    @NoArgsConstructor : 注在类上,提供类的无参构造
    @Setter : 注在属性上,提供 set 方法
    @Getter : 注在属性上,提供 get 方法
    @EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法
    @Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log
    */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserDetailsImpl implements UserDetails {
    
        private User user;
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return null;
        }
    
    	//重写获取密码的方法
        @Override
        public String getPassword() {
            return user.getPassword();
        }
    	
    	//重写获取用户名的方法
        @Override
        public String getUsername() {
            return user.getUsername();
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    2.LoginController调用LoginService实现login逻辑

    LoginController代码:

    package com.kob.backend.controller.user.account;
    
    
    import com.kob.backend.service.user.account.LoginService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Map;
    
    @RestController
    public class LoginController {
        @Autowired
        private LoginService loginService;
    
        @PostMapping("/user/account/token/")
        public Map<String, String> getToken(@RequestParam Map<String, String> map){
            String username = map.get("username");
            String password = map.get("password");
            System.out.println(username + ":" +password);
            return loginService.getToken(username, password);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    LoginServiceImpl实现LoginService服务:

    package com.kob.backend.service.impl.user.account;
    
    
    import com.kob.backend.pojo.User;
    import com.kob.backend.service.impl.utils.UserDetailsImpl;
    import com.kob.backend.service.user.account.LoginService;
    import com.kob.backend.utils.JwtUtil;
    import jdk.nashorn.internal.runtime.regexp.joni.ast.StringNode;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class LoginServiceImpl implements LoginService {
    
        @Autowired
        private AuthenticationManager authenticationManager;
    
        @Override
        public Map<String, String> getToken(String username, String password) {
    
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(username, password);
    
            Authentication authenticate = authenticationManager.authenticate(authenticationToken); //登陆失败会自动处理
    
            UserDetailsImpl loginUser = (UserDetailsImpl) authenticate.getPrincipal();
            User user = loginUser.getUser();
    
            String jwt = JwtUtil.createJWT(user.getId().toString());
    
            Map<String, String> map = new HashMap<>();
            //返回值是一个消息和jwt
            map.put("error_message", "success");
            map.put("token", jwt);
            return map;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    这里用到了JwtUtil这个工具类,使用了JWT:
    JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案

    package com.kob.backend.utils;
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.stereotype.Component;
    
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    import java.util.Date;
    import java.util.UUID;
    
    @Component
    public class JwtUtil {
        public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14;  // 有效期14天
        public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac";
    
        public static String getUUID() {
            return UUID.randomUUID().toString().replaceAll("-", "");
        }
    
        public static String createJWT(String subject) {
            JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
            return builder.compact();
        }
    
        private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            SecretKey secretKey = generalKey();
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            if (ttlMillis == null) {
                ttlMillis = JwtUtil.JWT_TTL;
            }
    
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            return Jwts.builder()
                    .setId(uuid)
                    .setSubject(subject)
                    .setIssuer("sg")
                    .setIssuedAt(now)
                    .signWith(signatureAlgorithm, secretKey)
                    .setExpiration(expDate);
        }
    
        public static SecretKey generalKey() {
            byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
            return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
        }
    
        public static Claims parseJWT(String jwt) throws Exception {
            SecretKey secretKey = generalKey();
            return Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(jwt)
                    .getBody();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    3.RegisterController调用RegisterService实现登录逻辑

    RegisterController代码:

    package com.kob.backend.controller.user.account;
    
    import com.kob.backend.service.user.account.RegisterService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Map;
    
    @RestController
    public class RegisterController {
    
        @Autowired
        private RegisterService registerService;
    
    	//这里指定了是一个PostMapping
        @PostMapping("user/account/register")
        public Map<String, String> register(@RequestParam Map<String, String> map){
            String username = map.get("username");
            String password = map.get("password");
            String confirmedPassword = map.get("confirmedPassword");
            //调用registerService中的
            return registerService.register(username, password, confirmedPassword);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    RegisterServiceImpl实现RegisterService服务

    涉及到往数据库中添加数据,故装配了UserMapper
    以及加密所需的PasswordEncoder

    package com.kob.backend.service.impl.user.account;
    
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.kob.backend.mapper.UserMapper;
    import com.kob.backend.pojo.User;
    import com.kob.backend.service.user.account.RegisterService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Service
    public class RegisterServiceImpl implements RegisterService {
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public Map<String, String> register(String username, String password, String confirmedPassword) {
            Map<String, String> map = new HashMap<>();
            if (username == null) {
                map.put("error_message", "用户名不能为空");
                return map;
            }
            if (password == null || confirmedPassword == null) {
                map.put("error_message", "密码不能为空");
                return map;
            }
    
            username = username.trim();
            if (username.length() == 0) {
                map.put("error_message", "用户名不能为空");
                return map;
            }
    
            if (password.length() == 0 || confirmedPassword.length() == 0) {
                map.put("error_message", "密码不能为空");
            }
    
            if (username.length() > 100) {
                map.put("error_message", "用户名长度不能大于100");
                return map;
            }
    
            if (password.length() > 100 || confirmedPassword.length() > 100) {
                map.put("error_message", "密码长度不能大于100");
                return map;
            }
    
            if (!password.equals(confirmedPassword)) {
                map.put("error_message", "两次输入的密码不一致");
                return map;
            }
    
    		//设置查询条件
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            //找到用户名为“username”的数据
            queryWrapper.eq("username", username);
            List<User> users = userMapper.selectList(queryWrapper);
            //如果不为空,则说明用户名已经存在
            if (!users.isEmpty()) {
                map.put("error_message", "用户名已存在");
                return map;
            }
    
    		//对密码进行加密
            String encodedPassword = passwordEncoder.encode(password);
            String photo = "https://cdn.acwing.com/media/user/profile/photo/1_lg_844c66b332.jpg";
            User user = new User(null, username, encodedPassword, photo);
            userMapper.insert(user);
    
            map.put("error_message", "success");
            return map;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    项目来源:acwing springboot框架课,对于项目整理一些知识点,便于学习,不做任何商业用途

  • 相关阅读:
    14.9 Socket 高效文件传输
    【EFK】基于K8S构建EFK+logstash+kafka日志平台
    GPT-3:现实版的“贾维斯”?还是真“人工”智能?
    大型架构设计的演进之路
    TMS320F28335调用官方库进行FFT频谱分析
    系统设计的11个考虑
    443-C++基础语法(121-130)
    TiFlash 函数下推必知必会丨十分钟成为 TiFlash Contributor
    java并发数据结构之CopyOnWriteArrayList
    SpringBoot第四课-Web开发
  • 原文地址:https://blog.csdn.net/qq_38293932/article/details/126591421