0


基于SpringBoot3.0中Spring Security + jwt 示例

pom包导入

<!--spring security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- java-jwt --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>

其余依赖包按需加入。

SecurityConfig配置

由于spring boot3.0废弃了extends WebSecurityConfigurerAdapter 的方式,所以这里采用添加@Bean新方式

packagecom.mia.common.config;importcom.mia.common.filter.JwtRequestFilter;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.HttpMethod;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.http.SessionCreationPolicy;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.web.SecurityFilterChain;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.CorsConfigurationSource;importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;importjava.util.List;@Slf4j@Configuration@EnableWebSecuritypublicclassSecurityConfig{@AutowiredprivateAuthenticationConfiguration authenticationConfiguration;@BeanpublicJwtRequestFilterauthenticationJwtTokenFilter(){returnnewJwtRequestFilter();}/**
     * 加密方式
     */@BeanpublicBCryptPasswordEncoderbCryptPasswordEncoder(){returnnewBCryptPasswordEncoder();}/**
     * 认证管理器,登录的时候参数会传给 authenticationManager
     *
     */@BeanpublicAuthenticationManagerauthenticationManager(AuthenticationConfiguration authenticationConfiguration)throwsException{return authenticationConfiguration.getAuthenticationManager();}@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{//关闭csrf
             http.csrf().disable()// 允许跨域(也可以不允许,看具体需求).cors().and()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 配置路径是否需要认证.authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers(HttpMethod.POST,"/account/**").permitAll()// 配置权限.antMatchers("/test").hasAuthority("admin")// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated().and().authenticationManager(authenticationManager(authenticationConfiguration)).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//此处为添加jwt过滤.addFilterBefore(authenticationJwtTokenFilter(),UsernamePasswordAuthenticationFilter.class);
        http.headers().frameOptions().disable();return http.build();}/**
     *跨域资源配置
     */@BeanpublicCorsConfigurationSourcecorsConfigurationSource(){finalCorsConfiguration configuration =newCorsConfiguration();//此处发现如果不加入自己的项目地址,会被拦截。
    configuration.setAllowedOriginPatterns(List.of("http://localhost:8083"));
        configuration.setAllowedMethods(List.of("GET","POST","OPTIONS","DELETE","PUT","PATCH"));
        configuration.setAllowedHeaders(List.of("Access-Control-Allow-Origin","X-Requested-With","Origin","Content-Type","Accept","Authorization"));
        configuration.setAllowCredentials(true);finalUrlBasedCorsConfigurationSource source =newUrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);return source;}}

JWT过滤

此处为以上过滤链中前置过滤中配置的过滤器,并且也是jwt与security主要集成使用的过滤类

packagecom.mia.common.filter;importcom.mia.common.utils.JwtTokenUtil;importcom.mia.loginProjet.account.UserDetailsServiceImpl;importjakarta.servlet.FilterChain;importjakarta.servlet.ServletException;importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.context.SecurityContextHolder;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.web.authentication.WebAuthenticationDetailsSource;importorg.springframework.util.StringUtils;importorg.springframework.web.filter.OncePerRequestFilter;importjava.io.IOException;publicclassJwtRequestFilterextendsOncePerRequestFilter{privatestaticfinalLogger log =LoggerFactory.getLogger(JwtRequestFilter.class);publicstaticfinalString BEARER ="Bearer ";@AutowiredprivateJwtTokenUtil jwtTokenUtil;@AutowiredprivateUserDetailsServiceImpl userDetailsService;/**
     * 从 Authorization 标头中,提取令牌
     *
     */privateStringparseJwt(HttpServletRequest request){String headerAuth = request.getHeader("Authorization");if(StringUtils.hasText(headerAuth)&& headerAuth.startsWith(BEARER)){return headerAuth.substring(BEARER.length());}returnnull;}@OverrideprotectedvoiddoFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain)throwsServletException,IOException{try{String jwt =parseJwt(request);if(jwt !=null&& jwtTokenUtil.validateJwtToken(jwt)){String username = jwtTokenUtil.getUsernameFromJwtToken(jwt);// 如果令牌存在(存在逻辑自己编写),则加载令牌UserDetails userDetails = userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authenticationToken =newUsernamePasswordAuthenticationToken(
                        userDetails,null, userDetails.getAuthorities());
                authenticationToken.setDetails(newWebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authenticationToken);}}catch(Exception e){
            log.error("无法设置用户认证:{}", e);}

        filterChain.doFilter(request, response);}}

JwtTokenUtil

此处为jwt操作封装了一些工具类,为生成token和解析token数据所用

packagecom.mia.common.utils;importio.jsonwebtoken.*;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.annotation.Configuration;importorg.springframework.stereotype.Component;importjava.util.Date;importjava.util.HashMap;importjava.util.Map;@Configuration@Component@Slf4jpublicclassJwtTokenUtil{/**
     * token的头key
     */publicstaticfinalString TOKEN_HEADER ="Authorization";/**
     * token前缀
     */publicstaticfinalString TOKEN_PREFIX ="Bearer ";/**
     * token 过期时间 30分钟
     */publicstaticfinallong EXPIRATION =1000*60*30;/**
     * 加密的key
     */publicstaticfinalString APP_SECRET_KEY ="secret";/**
     * 权限的声明key
     */privatestaticfinalString ROLE_CLAIMS ="role";/**
     * 生成token
     *
     * @param username 用户名
     * @param role 用户角色
     * @return token
     */publicstaticStringcreateToken(String username,String role){Map<String,Object> map =newHashMap<>();
        map.put(ROLE_CLAIMS, role);String token =Jwts.builder().setSubject(username)//.setClaims(map)// .claim("username", username).setIssuedAt(newDate()).setExpiration(newDate(System.currentTimeMillis()+ EXPIRATION)).signWith(SignatureAlgorithm.HS256, APP_SECRET_KEY).compact();return TOKEN_PREFIX +token;}/**
     * 获取当前登录用户用户名
     *
     * @param token
     * @return
     */publicstaticStringgetUsername(String token){Claims claims =Jwts.parser().setSigningKey(APP_SECRET_KEY).parseClaimsJws(token).getBody();return claims.get("username").toString();}/**
     * 获取当前登录用户角色
     *
     * @param token
     * @return
     */publicstaticStringgetUserRole(String token){Claims claims =Jwts.parser().setSigningKey(APP_SECRET_KEY).parseClaimsJws(token).getBody();return claims.get("rol").toString();}/**
     * 检查token是否过期
     *
     * @param  token token
     * @return boolean
     */publicstaticbooleanisExpiration(String token){Claims claims =Jwts.parser().setSigningKey(APP_SECRET_KEY).parseClaimsJws(token).getBody();return claims.getExpiration().before(newDate());}publicbooleanvalidateJwtToken(String authToken){try{Jwts.parser().setSigningKey(APP_SECRET_KEY).parseClaimsJws(authToken);returntrue;}catch(SignatureException e){
            log.error("Invalid JWT signature: {}", e.getMessage());}catch(MalformedJwtException e){
            log.error("Invalid JWT token: {}", e.getMessage());}catch(ExpiredJwtException e){
            log.error("JWT token is expired: {}", e.getMessage());}catch(UnsupportedJwtException e){
            log.error("JWT token is unsupported: {}", e.getMessage());}catch(IllegalArgumentException e){
            log.error("JWT claims string is empty: {}", e.getMessage());}returnfalse;}publicStringgetUsernameFromJwtToken(String token){returnJwts.parser().setSigningKey(APP_SECRET_KEY).parseClaimsJws(token).getBody().getSubject();}}

UserDetailsServiceImpl

这里需要自己去实现Security提供的UserDetailsService接口
重写loadUserByUsername方法,这里是验证token中信息是否可以允许访问的逻辑

packagecom.mia.loginProjet.account;importorg.springframework.security.core.GrantedAuthority;importorg.springframework.security.core.userdetails.User;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.stereotype.Service;importjava.util.ArrayList;importjava.util.List;@ServicepublicclassUserDetailsServiceImplimplementsUserDetailsService{@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{GrantedAuthority grantedAuthority=()->"roladmin";List<GrantedAuthority> grantedAuthorities=newArrayList<>();
        grantedAuthorities.add(grantedAuthority);//这里可以实现从数据库取,我为了偷懒,就没这么做  - -returnnewUser("admin","123",grantedAuthorities);}}

尝试自己实现一个登录接口

这里是我的例子,我偷懒写了一个登录接口,为了得到token,也为了以上过滤测试,可以实现成直接存在web头里,但我这里直接返回给前端处理,哈哈哈

packagecom.mia.loginProjet.account.controller;importcom.mia.common.dto.LoginPwdDto;importcom.mia.common.utils.JwtTokenUtil;importorg.springframework.web.bind.annotation.*;@RestControllerpublicclass accountController {@PostMapping("/account/login")publicStringlogin(@RequestBodyLoginPwdDto loginPwdDto){// 如果认证没通过,提示// 认证通过返回jwt//TODO 数据库验证用户账号逻辑  我懒没实现String jwt =JwtTokenUtil.createToken("admin","admin");System.out.println("JWT--------"+jwt);//放入请求头return jwt;}@GetMapping("/test")publicStringtest1(){return"200";}@GetMapping("/test2")publicStringtest2(){return"200";}}

至此结束示例,创作不易,可以收藏,但请不要抄袭

标签: spring boot java spring

本文转载自: https://blog.csdn.net/mia_tong1111/article/details/126459571
版权归原作者 mia_tong1111 所有, 如有侵权,请联系我们删除。

“基于SpringBoot3.0中Spring Security + jwt 示例”的评论:

还没有评论