Spring Security登录认证【前后端分离】

这篇博客详细介绍了如何在前后端分离的项目中配置Spring Security进行登录认证。从导入依赖、编写UserDetailsServiceImpl、配置SecurityConfig,到实现JSON格式的登录请求支持,包括登录成功、失败的回调处理,以及访问拦截的设置。通过这种方式,后端能够返回JSON信息给前端,由前端负责页面的跳转。

1. 导入依赖

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

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

2. 编写用户认证服务类UserDetailsServiceImpl

用户认证服务类需要复写UserDetailsService中的UserDetails -> loadUserByUsername(String username)方法

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
   
   
    private final MageService service; // 用户信息CRUD服务类

    public UserDetailsServiceImpl(MageService service) {
   
   
        this.service = service;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
   
   
        Mage usr = service.findByName(username); // 根据username查询用户
        if (usr != null) {
   
   
            return new User(usr.getMageName(), usr.getMagePassword(), AuthorityUtils.NO_AUTHORITIES);
        } else {
   
   
            throw new UsernameNotFoundException("当前用户不存在!");
        }
    }
}

loadUserByUsername(String username) 方法返回的类型是UserDetails,创建UserDetails类需要传3个参数

分别是username,password,Collection<? extends GrantedAuthority> authorities

authorities是用来设置用户权限访问的,这个参数即使表中没有也不能不传,如果需求不需要设置权限,可以传AuthorityUtils.NO_AUTHORITIES,表示没权限设置

3. 编写Spring Security配置类SecurityConfig

1. Spring Security的配置类需要继承WebSecurityConfigurerAdapter

@Configuration // 声明配置类
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   
   
}

2. 设置安全认证的加密方式,早期的Spring Security不是强制性的

/**
* 设置加密方式
*/
@Bean
PasswordEncoder passwordEncoder() {
   
   
    return new BCryptPasswordEncoder();
}

3. 用户认证方式

/**
* 用户认证
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   
   
    auth.userDetailsService(userDetailsService);
}

4. 安全认证的拦截和回调

前后端不分离,安全认证要做的事是拦截请求,根据配置的情况,跳转到指定页面

前后端分离,安全认证要做的事是拦截请求,根据配置的情况,返回json格式的提示信息给前端,让前端做跳转,后端就不再需要写跳转的代码了

1. 登录成功后

前后端不分离,使用.successForwardUrl() 或者.defaultSuccessUrl() 实现登录成功后的页面跳转

前后端分离,使用.successHandler()实现登录成功后向前端发送json格式的回馈信息

.formLogin()
    .loginProcessingUrl("/doLogin")
    .permitAll()
    .successHandler(new AuthenticationSuccessHandler() {
   
   
        @Override
        public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException
### 使用 Spring Security 实现前后端分离架构下的登录功能 为了实现前后端分离架构中的安全机制,Spring Security 提供了强大的工具集来管理认证和授权。在前后端分离的应用程序中,前端通常是一个独立的单页应用 (SPA),而后端提供 RESTful API 接口。 #### 配置依赖项 首先,在 `pom.xml` 文件中引入必要的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.0.RELEASE</version> </dependency> ``` #### 创建配置类 创建一个 Java 类用于配置 Spring Security 行为: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/login", "/api/register").permitAll() // 允许所有人访问注册和登录接口 .anyRequest().authenticated(); // 其他请求都需要身份验证 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 不创建会话 http.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` 此配置禁用了 CSRF 攻击防护[^1],因为大多数情况下 SPA 应用不需要它;设置了一些路径无需鉴权即可访问,并指定了其他所有请求都需经过身份验证。还设置了无状态模式,即服务器不会保存用户的 session 信息。 #### 自定义 JWT 认证过滤器 编写自定义的身份验证过滤器以解析来自 HTTP 请求头中的 JSON Web Token(JWT): ```java public class JwtAuthenticationFilter extends OncePerRequestFilter { private final String HEADER = "Authorization"; @Autowired private UserService userService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { try { String token = extractTokenFromHeader(request); if (!StringUtils.isEmpty(token)) { Claims claims = Jwts.parserBuilder() .setSigningKey("secret".getBytes()) .build() .parseClaimsJws(token).getBody(); UserDetails userDetails = new User(claims.getSubject(), "", Arrays.asList()); Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(auth); } } catch (Exception e){ logger.error(e.getMessage()); } chain.doFilter(request,response); } private String extractTokenFromHeader(HttpServletRequest request) { String headerAuth = request.getHeader(HEADER); if(StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { return headerAuth.substring(7); } return null; } } ``` 这段代码实现了从 HTTP 头部读取 Bearer Token 并对其进行解码的过程。如果成功,则将用户详情加载到上下文中以便后续操作使用[^3]。 #### 用户服务层 还需要有一个简单的用户信息服务用来获取用户数据: ```java @Service public interface UserService extends UserDetailsService { } @Service class CustomUserServiceImpl implements UserService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 查询数据库或其他存储介质获得对应用户名的信息... return new User(username,"password",{}); } } ``` 通过这种方式就可以完成基本的基于JWT的身份验证流程。当客户端发送带有有效令牌的请求时,该应用程序能够识别并授予适当级别的访问权限给调用方。
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值