SpringSecurity6怎么用

目录

SpringSecurity依赖

jwt依赖

SecurityConfig配置类

UserDetailsService

UserDetails

 jwt工具类

UserLoginController

JwtAuthenticationFilter

SpringContextUtils

添加自定义token验证过滤器

AuthEntryPointHandler

AuthAccessDeniedHandler

添加自定义处理器

静态资源放行


SpringSecurity依赖

<!--SpringSecurity起步依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

jwt依赖

<!--jwt令牌-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

SecurityConfig配置类

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
 
/**
 * @Description: SpringSecurity配置类
 * @Author: 翰戈.summer
 * @Date: 2023/11/17
 * @Param:
 * @Return:
 */
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
 
    private final UserDetailsService userDetailsService;
 
    /**
     * 加载用户信息
     */
    @Bean
    public UserDetailsService userDetailsService() {
        return userDetailsService;
    }
 
    /**
     * 密码编码器
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
 
    /**
     * 身份验证管理器
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }
 
    /**
     * 处理身份验证
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }
 
    /**
     * @Description: 配置SecurityFilterChain过滤器链
     * @Author: 翰戈.summer
     * @Date: 2023/11/17
     * @Param: HttpSecurity
     * @Return: SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/api/user/login").permitAll() //登录放行
                .anyRequest().authenticated()
        );
        httpSecurity.authenticationProvider(authenticationProvider());
 
        //禁用登录页面
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        //禁用登出页面
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //禁用session
        httpSecurity.sessionManagement(AbstractHttpConfigurer::disable);
        //禁用httpBasic
        httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
        //禁用csrf保护
        httpSecurity.csrf(AbstractHttpConfigurer::disable);
 
        return httpSecurity.build();
    }
}

UserDetailsService

import com.demo.mapper.AuthorityMapper;
import com.demo.mapper.UserMapper;
import com.demo.pojo.AuthorityEntity;
import com.demo.pojo.UserEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
 
import java.util.List;
import java.util.StringJoiner;
 
/**
 * @Description: 用户登录
 * @Author: 翰戈.summer
 * @Date: 2023/11/16
 * @Param:
 * @Return:
 */
@Service
@RequiredArgsConstructor
public class UserLoginDetailsServiceImpl implements UserDetailsService {
 
    private final UserMapper userMapper;
    private final AuthorityMapper authorityMapper;
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity userEntity = userMapper.selectUserByUsername(username);
 
        List<AuthorityEntity> authorities = authorityMapper.selectAuthorityByUsername(username);
        StringJoiner stringJoiner = new StringJoiner(",", "", "");
 
        authorities.forEach(authority -> stringJoiner.add(authority.getAuthorityName()));
 
        return new User(userEntity.getUsername(), userEntity.getPassword(),
                AuthorityUtils.commaSeparatedStringToAuthorityList(stringJoiner.toString())
        );
    }
}

UserDetails

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
 
import java.util.Collection;
 
/**
 * @Description: SpringSecurity用户实体类
 * @Author: 翰戈.summer
 * @Date: 2023/11/18
 * @Param:
 * @Return:
 */
@NoArgsConstructor
@AllArgsConstructor
public class UserDetailsEntity implements UserDetails {
 
    private String username;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;
 
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }
 
    @Override
    public String getPassword() {
        return password;
    }
 
    @Override
    public String getUsername() {
        return username;
    }
 
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
 
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
 
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
 
    @Override
    public boolean isEnabled() {
        return true;
    }
 
    @Override
    public String toString() {
        return "UserDetailsEntity{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", authorities=" + authorities +
                '}';
    }
}

 jwt工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
 
import java.util.Date;
import java.util.Map;
 
/**
 * @Description: 生成和解析jwt令牌
 * @Author: 翰戈.summer
 * @Date: 2023/11/16
 * @Param:
 * @Return:
 */
@Component
@RequiredArgsConstructor
public class JwtUtils {
 
    private final JwtProperties jwtProperties;
 
    /**
     * @Description: 生成令牌
     * @Author: 翰戈.summer
     * @Date: 2023/11/16
     * @Param: Map
     * @Return: String jwt
     */
    public String getJwt(Map<String, Object> claims) {
 
        String signingKey = jwtProperties.getSigningKey();
        Long expire = jwtProperties.getExpire();
 
        return Jwts.builder()
                .setClaims(claims) //设置载荷内容
                .signWith(SignatureAlgorithm.HS256, signingKey) //设置签名算法
                .setExpiration(new Date(System.currentTimeMillis() + expire)) //设置有效时间
                .compact();
    }
 
    /**
     * @Description: 解析令牌
     * @Author: 翰戈.summer
     * @Date: 2023/11/16
     * @Param: String jwt
     * @Return: Claims claims
     */
    public Claims parseJwt(String jwt) {
 
        String signingKey = jwtProperties.getSigningKey();
 
        return Jwts.parser()
                .setSigningKey(signingKey) //指定签名密钥
                .parseClaimsJws(jwt) //开始解析令牌
                .getBody();
    }
}

UserLoginController

import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
 
/**
 * @Description: 用户登录操作相关接口
 * @Author: 翰戈.summer
 * @Date: 2023/11/20
 * @Param:
 * @Return:
 */
@RestController
@RequestMapping("/api/user/login")
@RequiredArgsConstructor
public class UserLoginController {
 
    private final AuthenticationManager authenticationManager;
 
    private final JwtUtils jwtUtils;
 
    @PostMapping
    public Result<String> doLogin(@RequestBody UserLoginDTO userLoginDTO) {
        try {
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userLoginDTO.getUsername(), userLoginDTO.getPassword());
            Authentication authentication = authenticationManager.authenticate(auth);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
 
            //获取用户权限信息
            String authorityString = "";
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                authorityString = authority.getAuthority();
            }
 
            //用户身份验证成功,生成并返回jwt令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put("username", userDetails.getUsername());
            claims.put("authorityString", authorityString);
            String jwtToken = jwtUtils.getJwt(claims);
            return Result.success(jwtToken);
        } catch (Exception ex) {
            //用户身份验证失败,返回登陆失败提示
            return Result.error("用户名或密码错误!");
        }
    }
}

JwtAuthenticationFilter

import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;
 
import java.io.IOException;
import java.util.Collections;
 
/**
 * @Description: 自定义token验证过滤器,验证成功后将用户信息放入SecurityContext上下文
 * @Author: 翰戈.summer
 * @Date: 2023/11/18
 * @Param:
 * @Return:
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
 
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException {
        try {
            //获取请求头中的token
            String jwtToken = request.getHeader("token");
            if (!StringUtils.hasLength(jwtToken)) {
                //token不存在,交给其他过滤器处理
                filterChain.doFilter(request, response);
                return; //结束方法
            }
 
            //过滤器中无法初始化Bean组件,使用上下文获取
            JwtUtils jwtUtils = SpringContextUtils.getBean("jwtUtils");
            if (jwtUtils == null) {
                throw new RuntimeException();
            }
 
            //解析jwt令牌
            Claims claims;
            try {
                claims = jwtUtils.parseJwt(jwtToken);
            } catch (Exception ex) {
                throw new RuntimeException();
            }
 
            //获取用户信息
            String username = (String) claims.get("username"); //用户名
            String authorityString = (String) claims.get("authorityString"); //权限信息
 
            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    username, null,
                    Collections.singleton(new SimpleGrantedAuthority(authorityString))
            );
 
            //将用户信息放入SecurityContext上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);
 
            filterChain.doFilter(request, response);
        } catch (Exception ex) {
            //过滤器中抛出的异常无法被全局异常处理器捕获,直接返回错误结果
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            String value = new ObjectMapper().writeValueAsString(Result.error("用户未登录!"));
            response.getWriter().write(value);
        }
    }
}

SpringContextUtils

import jakarta.annotation.Nonnull;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
 
/**
 * @Description: 用于创建上下文,实现ApplicationContextAware接口
 * @Author: 翰戈.summer
 * @Date: 2023/11/17
 * @Param:
 * @Return:
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {
 
    private static ApplicationContext applicationContext;
 
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
 
    @Override
    public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }
 
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        if (applicationContext == null) {
            return null;
        }
        return (T) applicationContext.getBean(name);
    }
}

添加自定义token验证过滤器

    /**
     * @Description: 配置SecurityFilterChain过滤器链
     * @Author: 翰戈.summer
     * @Date: 2023/11/17
     * @Param: HttpSecurity
     * @Return: SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/api/user/login").permitAll() //登录放行
                .anyRequest().authenticated()
        );
        httpSecurity.authenticationProvider(authenticationProvider());
 
        //禁用登录页面
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        //禁用登出页面
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //禁用session
        httpSecurity.sessionManagement(AbstractHttpConfigurer::disable);
        //禁用httpBasic
        httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
        //禁用csrf保护
        httpSecurity.csrf(AbstractHttpConfigurer::disable);
 
        //通过上下文获取AuthenticationManager
        AuthenticationManager authenticationManager = SpringContextUtils.getBean("authenticationManager");
        //添加自定义token验证过滤器
        httpSecurity.addFilterBefore(new JwtAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);
 
        return httpSecurity.build();
    }

AuthEntryPointHandler

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
 
import java.io.IOException;
 
/**
 * @Description: 自定义用户未登录的处理(未携带token)
 * @Author: 翰戈.summer
 * @Date: 2023/11/19
 * @Param:
 * @Return:
 */
@Component
public class AuthEntryPointHandler implements AuthenticationEntryPoint {
 
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        String value = new ObjectMapper().writeValueAsString(Result.error("未携带token!"));
        response.getWriter().write(value);
    }
}

AuthAccessDeniedHandler

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
 
import java.io.IOException;
 
/**
 * @Description: 自定义用户权限不足的处理
 * @Author: 翰戈.summer
 * @Date: 2023/11/19
 * @Param:
 * @Return:
 */
@Component
public class AuthAccessDeniedHandler implements AccessDeniedHandler {
 
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        String value = new ObjectMapper().writeValueAsString(Result.error("权限不足!"));
        response.getWriter().write(value);
    }
}

添加自定义处理器

    /**
     * @Description: 配置SecurityFilterChain过滤器链
     * @Author: 翰戈.summer
     * @Date: 2023/11/17
     * @Param: HttpSecurity
     * @Return: SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/api/user/login").permitAll() //登录放行
                .anyRequest().authenticated()
        );
        httpSecurity.authenticationProvider(authenticationProvider());
 
        //禁用登录页面
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        //禁用登出页面
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //禁用session
        httpSecurity.sessionManagement(AbstractHttpConfigurer::disable);
        //禁用httpBasic
        httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
        //禁用csrf保护
        httpSecurity.csrf(AbstractHttpConfigurer::disable);
 
        //通过上下文获取AuthenticationManager
        AuthenticationManager authenticationManager = SpringContextUtils.getBean("authenticationManager");
        //添加自定义token验证过滤器
        httpSecurity.addFilterBefore(new JwtAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);
 
        //自定义处理器
        httpSecurity.exceptionHandling(exceptionHandling -> exceptionHandling
                .accessDeniedHandler(authAccessDeniedHandler) //处理用户权限不足
                .authenticationEntryPoint(authEntryPointHandler) //处理用户未登录(未携带token)
        );
 
        return httpSecurity.build();
    }

静态资源放行

    /**
     * 静态资源放行
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers(
                "/doc.html",
                "/doc.html/**",
                "/v3/api-docs",
                "/v3/api-docs/**",
                "/webjars/**",
                "/authenticate",
                "/swagger-ui.html/**",
                "/swagger-resources",
                "/swagger-resources/**"
        );
    }
  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值