springboot+vue实现前后端分离之后端spring部分(spring boot 2.5.4/vue.js 3.2.4)

一,前、后端项目的代码地址

前端:
https://gitee.com/liuhongdi/jwtweb
后端:
https://gitee.com/liuhongdi/jwtdemo

 说明:前端部分的安装第三方库等说明请参见:

https://www.cnblogs.com/architectforest/p/15185275.html

说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

         对应的源码可以访问这里获取: https://github.com/liuhongdi/
         或: https://gitee.com/liuhongdi

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,后端项目配置信息说明:

1,pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lhd</groupId>
    <artifactId>jwtdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jwtdemo</name>
    <description>jwtdemo</description>
    <properties>
        <java.version>16</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--security begin-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--jjwt begin-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!--fastjson begin-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <!--jaxb-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2,application.yml

#server
server:
  port: 8000
  error:
    include-stacktrace: always

 三,java代码说明

1,controller/HomeController.java

@Controller
@RequestMapping("/home")
public class HomeController {

    //session详情
    @GetMapping("/home")
    @ResponseBody
    public Result home() {
        Map<String, String> data = new HashMap<String, String>();
        data.put("username", SessionUtil.getCurrentUserName());
        data.put("userid", String.valueOf(SessionUtil.getCurrentUser().getUserid()));
        data.put("nickname", SessionUtil.getCurrentUser().getNickname());
        data.put("roles", SessionUtil.getCurrentUser().getAuthorities().toString());
        return Result.success(data);
    }
}

返回用户的session信息

2,jwt/JwtAuthticationFilter.java

@Component
public class JwtAuthticationFilter implements Filter {

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private JwtUserDetailsService userDetailsService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("----------------AuthticationFilter init");
    }
    //过滤功能
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //得到当前的url
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String path = request.getServletPath();
        //如果是登录的url,需要进行验证
        if (path.equals("/auth/authenticate")) {
             //得到请求的post参数
            String username = "";
            String password = "";
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
                StringBuffer sb=new StringBuffer();
                String s=null;
                while((s=br.readLine())!=null){
                    sb.append(s);
                }
                JSONObject jsonObject = JSONObject.parseObject(sb.toString());
                username = jsonObject.getString("username");
                password = jsonObject.getString("password");
                //System.out.println("name:"+name+" age:"+age);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String authResult = "";
            try{
                authResult = authenticate(username,password);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if ("success".equals(authResult)) {
                final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                final String token = jwtTokenUtil.generateToken(userDetails);
                Map<String, String> mapData = new HashMap<String, String>();
                mapData.put("token", token);
                ServletUtil.printRestResult(Result.success(mapData));
            } else if ("badcredential".equals(authResult)){
                ServletUtil.printRestResult(Result.error(ResponseCode.LOGIN_FAIL));
            } else {
                ServletUtil.printRestResult(Result.error(ResponseCode.ERROR));
            }
            return;
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void destroy() {
        System.out.println("----------------filter destroy");
    }

    //通过用户名密码进行验证
    private String authenticate(String username, String password) throws Exception {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            return "success";
        } catch (DisabledException e) {
            throw new Exception("USER_DISABLED", e);
        } catch (BadCredentialsException e) {
            System.out.println("BadCredentialsException");
            System.out.println(e.toString());
            return "badcredential";
        }
    }
}

说明:登录验证的url: /auth/authenticate是在这个filter中进行的

3,jwt/JwtRequestFilter.java

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization");
        String username = null;
        String jwtToken = null;
        // JWT Token 获取请求头部的 Bearer
        System.out.println("filter:header:"+requestTokenHeader);
        // only the Token
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            //System.out.println("filter :requestTokenHeader not null and start with bearer");
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                System.out.println("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                System.out.println("JWT Token has expired");
            } catch (MalformedJwtException e) {
                System.out.println("JWT Token MalformedJwtException");
            }
        } else {
            //System.out.println("filter :requestTokenHeader is null || not start with bearer");
            //logger.warn("JWT Token does not begin with Bearer String");
        }

        // 验证,
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            //System.out.println("filter:username!=null");
            UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
            // JWT 验证通过 使用Spring Security 管理
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                //System.out.println("usernamePasswordAuthenticationToken:"+usernamePasswordAuthenticationToken.toString());
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            } else {
               // System.out.println("jwtTokenUtil.validateToken not success");
            }
        }
        chain.doFilter(request, response);
    }
}

这个filter实现在针对jwt token的验证,把token转化成了相应的用户信息保存到了session中

4,security/WebSecurityConfig.java

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserAuthenticationEntryPoint userAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Resource
    private UserAccessDeniedHandler userAccessDeniedHandler;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // configure AuthenticationManager so that it knows from where to load
        // user for matching credentials
        // Use BCryptPasswordEncoder
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // 本示例不需要使用CSRF
        httpSecurity.csrf().disable();
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // 认证页面不需要权限
        httpSecurity.authorizeRequests().
                antMatchers("/auth/authenticate").permitAll().
                //其他页面
                anyRequest().authenticated();
        //access deny
        httpSecurity.exceptionHandling().accessDeniedHandler(userAccessDeniedHandler);
        //unauthorized
        httpSecurity.exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPoint);
        //验证请求是否正确
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

注意其中把jwt的过滤器添加到了HttpSecurity中

5,其他代码请参见gitee

四,查看spring boot的版本:

  .   ____          _            __ _ _
 /\ / ___'_ __ _ _(_)_ __  __ _    
( ( )\___ | '_ | '_| | '_ / _` |    
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.4)
原文地址:https://www.cnblogs.com/architectforest/p/15185416.html