springboot+vue实现前后端分离之后端spring部分(spring boot 2.5.4/vue.js 3.2.4)
一,前、后端项目的代码地址
前端:
https://gitee.com/liuhongdi/jwtweb
后端:
https://gitee.com/liuhongdi/jwtdemo
说明:前端部分的安装第三方库等说明请参见:
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/28/springboot-vue-shi-xian-qian-hou-duan-fen-li-zhi-hou-duan/
对应的源码可以访问这里获取: 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)