spring boot+spring security+jwt+vue整合前后端分离token权限认证项目详细过程代码 含AES加密

准备前提条件:已搭好一个spring boot后台项目及vue前台项目

目录

一、后台

1、依赖

2、继承WebSecurityConfigurerAdapter适配器

3、自定义用户名密码校验 MyAuthenticationProvider

4、登录成功处理逻辑 CustomizeAuthenticationSuccessHandler

5、登录失败处理逻辑 CustomizeAuthenticationFailureHandler

6、匿名用户访问无权限资源时的异常处理 CustomizeAuthenticationEntryPoint

7、会话失效(账号被挤下线)处理逻辑 CustomizeSessionInformationExpiredStrategy

8、登出成功处理逻辑 CustomizeLogoutSuccessHandler

9、UserDetailsService 的实现 UserDetailsServiceImpl

10、访问权限过滤器 AuthorizationFilter

11、token处理工具类 TokenUtil

12、Aes加密工具类 AesEncryptUtil

13、统一消息返回体工具类 JsonResult

14、实体 UsersDomain 字段注解偷懒没加全

15、实体 RoleDomain 字段注解偷懒没加全

二、前台

1、main.js

2、router/index.js

3、store/index.js

4、AES加密解密方法utils/secret.js

5、登录页 login/index


一、后台

1、依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</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-security</artifactId>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>
<dependency>
    <groupId>net.minidev</groupId>
    <artifactId>json-smart</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
<dependency>
    <groupId>net.sf.json-lib</groupId>
    <artifactId>json-lib</artifactId>
    <version>2.4</version>
    <classifier>jdk15</classifier>
</dependency>

2、继承WebSecurityConfigurerAdapter适配器

import com.example.office.filter.AuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;
//    自定义用户名密码校验
    @Autowired
    MyAuthenticationProvider myAuthenticationProvider;
    //登录成功处理逻辑
    @Autowired
    CustomizeAuthenticationSuccessHandler authenticationSuccessHandler;

    //登录失败处理逻辑
    @Autowired
    CustomizeAuthenticationFailureHandler authenticationFailureHandler;

    //匿名用户访问无权限资源时的异常
    @Autowired
    CustomizeAuthenticationEntryPoint authenticationEntryPoint;

    //会话失效(账号被挤下线)处理逻辑
    @Autowired
    CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;

    //登出成功处理逻辑
    @Autowired
    CustomizeLogoutSuccessHandler logoutSuccessHandler;

    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(myAuthenticationProvider);
//        auth.userDetailsService(userDetailsService());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeRequests().
                // 所以请求都需要认证
                anyRequest().authenticated().
                // 登出
                and().logout().logoutUrl("/logout").
                permitAll(). // 允许所有用户
                logoutSuccessHandler(logoutSuccessHandler). // 登出成功处理逻辑
                // deleteCookies("JESSIONID"). // 登出之后删除cookie
                // 登入
and().formLogin().loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password").permitAll().
                successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler).
                // 记住我
                and().rememberMe().tokenRepository(getPersistentTokenRepository()).
                tokenValiditySeconds(15*60*1000).
                // 异常处理(权限拒绝、登录失效等)
                and().exceptionHandling().
                authenticationEntryPoint(authenticationEntryPoint). // 匿名用户访问无权限资源时的异常处理
                // 访问过滤器
                and().addFilter(new AuthorizationFilter(authenticationManager())).httpBasic().
                // 会话管理
                and().sessionManagement().
                maximumSessions(1). // 同一账号同时登录最大用户数
                expiredSessionStrategy(sessionInformationExpiredStrategy); // 会话失效(账号被挤下线)处理逻辑
        // 禁用缓存
        http.headers().cacheControl();
    }
}

3、自定义用户名密码校验 MyAuthenticationProvider

import com.example.office.utils.AesEncryptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 自定义用户名密码校验
 */
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 获取用户输入的用户名和密码
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        // 登录密码前端加密传输,需先解密
        password = AesEncryptUtil.decrypt(password);
        // 获取封装用户的信息
        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            throw new BadCredentialsException("查无此用户");
        }
        // 进行密码的对比
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean flag = bCryptPasswordEncoder.matches(password, user.getPassword());
        // 校验通过
        if (flag) {
            // 将权限信息也封装进去
            return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
        } else {
            throw new BadCredentialsException("用户名或密码错误!");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

4、登录成功处理逻辑 CustomizeAuthenticationSuccessHandler

import com.example.office.utils.JsonResult;
import com.example.office.utils.TokenUtil;
import net.minidev.json.JSONValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 登录成功请求处理
 */
@Component
public class CustomizeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final static Logger log = LoggerFactory.getLogger(CustomizeAuthenticationSuccessHandler.class);

   
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring BootSpring Security可以很好地结合使用来实现RESTful API的认证。而JWT(JSON Web Token)是一种用于认证和授权的安全传输方式。 要在Spring Boot中实现JWT认证,可以遵循以下步骤: 1. 添加依赖:在`pom.xml`文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 创建JWT工具类:创建一个JWT工具类来生成和解析JWT。可以使用JJWT库来简化这个过程。 3. 创建认证过滤器:创建一个继承自`OncePerRequestFilter`的认证过滤器,在该过滤器中检查请求中的JWT,并进行认证。 4. 配置Spring Security:将认证过滤器添加到Spring Security的配置中,以便在每个请求到达之前进行JWT认证。 5. 创建登录接口:创建一个登录接口,用于验证用户的身份并生成JWT。 这是一个简单的示例代码,说明如何在Spring Boot中实现JWT认证: ```java // JWT工具类 public class JwtUtils { private static final String SECRET_KEY = "your-secret-key"; private static final long EXPIRATION_TIME = 864_000_000; // 10天 public static String generateToken(Authentication authentication) { UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal(); Date expirationDate = new Date(System.currentTimeMillis() + EXPIRATION_TIME); return Jwts.builder() .setSubject(userPrincipal.getUsername()) .setIssuedAt(new Date()) .setExpiration(expirationDate) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static String getUsernameFromToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody() .getSubject(); } public static boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; } catch (SignatureException | MalformedJwtException | ExpiredJwtException | UnsupportedJwtException | IllegalArgumentException e) { return false; } } } // 认证过滤器 public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtUtils jwtUtils; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = request.getHeader("Authorization"); if (StringUtils.hasText(authorizationHeader) && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); if (jwtUtils.validateToken(token)) { String username = jwtUtils.getUsernameFromToken(token); UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } } // Spring Security配置类 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtAuthenticationFilter jwtAuthenticationFilter; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } // 登录接口 @RestController public class AuthController { @Autowired private AuthenticationManager authenticationManager; @PostMapping("/login") public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()) ); SecurityContextHolder.getContext().setAuthentication(authentication); String token = JwtUtils.generateToken(authentication); return ResponseEntity.ok(new JwtResponse(token)); } } // 登录请求DTO public class LoginRequest { private String username; private String password; // getters and setters } // JWT响应DTO public class JwtResponse { private String token; // constructor and getter } // 用户详情实现类 @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username)); return UserDetailsImpl.build(user); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值