亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

springSecurity+jwt使用小結(jié)

 更新時(shí)間:2024年11月25日 09:52:15   作者:v_lazy  
本文介紹了使用Spring Security與JWT進(jìn)行身份驗(yàn)證和授權(quán),實(shí)現(xiàn)用戶認(rèn)證和授權(quán)的詳細(xì)流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

(1) jdk版本和springboot版本

<properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <springboot.version>3.1.5</springboot.version>
    </properties>

(2) 流程說明(可以對(duì)照代碼實(shí)現(xiàn))

1.springboot啟動(dòng)時(shí),會(huì)先加載WebSecurityConfig配置
(1)WebSecurityConfig里會(huì)跳過指定的url【requestMatchers("/auth/login").permitAll()】
(2)增加過濾器【.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)】
(3)綁定認(rèn)證失敗類:exceptionHandling(exce->exce.authenticationEntryPoint(unauthorizedHandler))
(4)綁定權(quán)限校驗(yàn)失敗類:exceptionHandling(exce->exce.accessDeniedHandler(wAccessDeniedHandler))

2.當(dāng)/auth/login請(qǐng)求進(jìn)入時(shí),會(huì)先到JwtAuthenticationTokenFilter過濾器,判斷請(qǐng)求頭中是否有token,因?yàn)闆]有token直接filterChain.doFilter(request, response)下一步,又因?yàn)樵赪ebSecurityConfig配置了過濾,不會(huì)進(jìn)入異常類,會(huì)直接到達(dá)AuthController,會(huì)進(jìn)入到LoginServiceImpl類,根據(jù)用戶名和密碼進(jìn)行校驗(yàn)【authenticationManager.authenticate(authentication),真正進(jìn)行校驗(yàn)的實(shí)現(xiàn)類JwtAuthenticationProvider】,校驗(yàn)通過則返回token,否則拋出異常,返回錯(cuò)誤信息。

3.當(dāng)其它請(qǐng)求進(jìn)入時(shí),也會(huì)先到JwtAuthenticationTokenFilter過濾器,如果有token,則解析token,獲取用戶信息,然后設(shè)置到SecurityContextHolder中,如果解析失敗,則拋出異常,進(jìn)入異常處理類,返回錯(cuò)誤信息。如果沒有token,則會(huì)被攔截,進(jìn)入異常處理類,返回錯(cuò)誤信息

(3) 代碼實(shí)現(xiàn)

1.spring Security配置WebSecurityConfig

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {

    @Autowired
    private UnauthorizedHandler unauthorizedHandler;
    @Autowired
    private WAccessDeniedHandler wAccessDeniedHandler;


    /**
     * 認(rèn)證管理
     * @param configuration
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    /**
     * 認(rèn)證過濾器
     * @return
     */
    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 密碼加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 權(quán)限校驗(yàn)
     * @return
     */
    @Bean("per")
    public PermissionCheckServiceImpl permissionCheckServiceImpl(){
        return new PermissionCheckServiceImpl();
    }

    /**
     * 配置安全過濾器鏈
     * @param httpSecurity
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(sessionManager-> sessionManager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize->authorize
                        .requestMatchers("/auth/login").permitAll()
                        .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                .httpBasic(Customizer.withDefaults())
                //禁用緩存
                .headers(header->header.cacheControl(HeadersConfigurer.CacheControlConfig::disable))
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                //綁定認(rèn)證失敗類
//                .exceptionHandling(exce->exce.authenticationEntryPoint(unauthorizedHandler))
                //鑒權(quán)失敗類
                .exceptionHandling(exce->exce.accessDeniedHandler(wAccessDeniedHandler))
                .build();
    }
}

2.jwt身份攔截器JwtAuthenticationTokenFilter

import cn.hutool.core.convert.NumberWithFormat;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 *
 * 身份驗(yàn)證攔截器
 */
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException, UsernameNotFoundException {
        //從頭中獲取token(jwt)
        String authorization = request.getHeader("Authorization");
        //判斷token
        if(StringUtils.isBlank(authorization)){
            filterChain.doFilter(request, response);
            return ;
        }
        //校驗(yàn)token格式
        if(!authorization.startsWith("Bearer ")){
            log.error(RespCodeEnum.TOKEN_ERROR.getDesc());
            response(response, RespCodeEnum.TOKEN_ERROR);
            return ;
        }
        //獲取jwt數(shù)據(jù)
        String token = authorization.split(" ")[1];
        if(!JWTUtil.verify(token, AuthConstant.JWT_KEY.getBytes(StandardCharsets.UTF_8))){
            log.error(RespCodeEnum.TOKEN_ERROR.getDesc());
            response(response, RespCodeEnum.TOKEN_ERROR);
        }
        //獲取用戶名和過期時(shí)間
        JWT jwt = JWTUtil.parseToken(token);
        String loginname = (String) jwt.getPayload("loginname");
        //獲取jwt中的過期時(shí)間
        long exp = ((NumberWithFormat) jwt.getPayload("exp")).longValue();

        //判斷是否已經(jīng)過期
        if(System.currentTimeMillis() / 1000 > exp){
            log.error(RespCodeEnum.TOKEN_EXP.getDesc());
            response(response, RespCodeEnum.TOKEN_EXP);
            return;
        }
        //獲取用戶信息
        UserDetailsBo userDetails = (UserDetailsBo)userDetailsService.loadUserByUsername(loginname);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(),
                userDetails.getPassword(), userDetails.getAuthorities());
        authenticationToken.setDetails(userDetails.getUserDto());
        //將認(rèn)證過了憑證保存到security的上下文中以便于在程序中使用
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request,response);
    }

    private void response(@NotNull HttpServletResponse response,@NotNull RespCodeEnum error) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 或者使用自定義狀態(tài)碼
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(JSONUtil.toJsonStr(ResponseDto.fail(error)));
    }
}

3.自定義身份驗(yàn)證失敗處理器類UnauthorizedHandler

import cn.hutool.json.JSONUtil;
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;

/**
 * 
 * 自定義身份驗(yàn)證失敗處理器
 */
@Component
public class UnauthorizedHandler implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 設(shè)置響應(yīng)狀態(tài)碼為401(未授權(quán))
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        // 設(shè)置響應(yīng)內(nèi)容類型
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        // 響應(yīng)體內(nèi)容,可以根據(jù)需要自定義
        ResponseDto fail = ResponseDto.fail(RespCodeEnum.ACCESS_DENIED);
        response.getWriter().write(JSONUtil.toJsonStr(fail));
    }
}

4.權(quán)限認(rèn)證失敗處理類WAccessDeniedHandler

import jakarta.servlet.ServletException;
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;

/**
 * 
 * 權(quán)限認(rèn)證失敗處理
 */
@Component
public class WAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().print("認(rèn)證失敗");
        response.getWriter().flush();
    }
}

5.JwtAuthenticationProvider實(shí)現(xiàn)AuthenticationProvider接口,進(jìn)行用戶身份驗(yàn)證

import org.apache.commons.lang3.StringUtils;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 用戶身份驗(yàn)證
 * 
 */
@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) {
        String username = String.valueOf(authentication.getPrincipal());
        String password = String.valueOf(authentication.getCredentials());

        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if(userDetails != null && StringUtils.isNotBlank(userDetails.getPassword())
        && userDetails.getPassword().equals(password)){
            return new UsernamePasswordAuthenticationToken(username,password,authentication.getAuthorities());
        }
        throw new BusinessException(RespCodeEnum.NAME_OR_PASSWORD_ERROR);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.equals(authentication);
    }
}

6.繼承UserDetailsService,從數(shù)據(jù)庫獲取用戶信息

import lombok.RequiredArgsConstructor;
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;

@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
    private final IUserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDto user = userService.selectUserByLoginName(username);
        return new UserDetailsBo(user);
    }
}


7.自定義UserDetailsBo類,繼承UserDetails

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.stream.Collectors;


@Component
public class UserDetailsBo implements UserDetails {

    private UserDto userDto;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        return userDto.getPermissionName().stream()
                .map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        return userDto.getPassword();
    }

    @Override
    public String getUsername() {
        return userDto.getLoginName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public UserDetailsBo(){}

    public UserDetailsBo(UserDto userDto){
        this.userDto = userDto;
    }

    public UserDto getUserDto() {
        return userDto;
    }

    public void setUserDto(UserDto userDto) {
        this.userDto = userDto;
    }
}

8.自定義權(quán)限校驗(yàn)PermissionCheckServiceImpl

import cn.hutool.core.util.ArrayUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;


public class PermissionCheckServiceImpl {

    public PermissionCheckServiceImpl(){}

    public boolean havePermission(String... permissions)
    {
        if(permissions == null){
            return true;
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null){
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            List<String> authList = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
            for(int i = 0;i < permissions.length;i++){
                if(authList.contains(permissions[i])){
                    return true;
                }
            }
        }
        return false;
    }
}

9.實(shí)現(xiàn)登錄接口和接口權(quán)限校驗(yàn)

import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 認(rèn)證控制器
 *
 */

@RestController
@RequestMapping("auth")
@RequiredArgsConstructor
public class AuthController {

    private final ILoginService loginService;

    /**
     * 登錄
     * @param req 請(qǐng)求參數(shù)
     * @return 返回token
     */
    @GetMapping("login")
    public String login(@Validated UserLoginAccPwdDto req) {
        return loginService.loginAccPwd(req);
    }

    @PreAuthorize("@per.havePermission('user','admin')")
    @GetMapping("test")
    public UserInfoVo test() {
        return null;
    }
}

10.登錄實(shí)現(xiàn)

import cn.hutool.jwt.JWT;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.Date;


@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements ILoginService {

    private final AuthenticationManager authenticationManager;

    @Override
    public String loginAccPwd(UserLoginAccPwdDto login) {
        //登錄驗(yàn)證
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(login.getLoginName(), login.getPassword());
        authenticationManager.authenticate(authentication);
        //生成jwt token
        String token = JWT.create()
                .setPayload("loginname", login.getLoginName())
                .setKey(AuthConstant.JWT_KEY.getBytes(StandardCharsets.UTF_8))
                //過期時(shí)間3小時(shí)
                .setExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
                .sign();
        return token;
    }
}

到此這篇關(guān)于springSecurity+jwt使用小結(jié)的文章就介紹到這了,更多相關(guān)springSecurity使用jwt內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希

相關(guān)文章

  • 源碼解讀Spring-Integration執(zhí)行過程

    源碼解讀Spring-Integration執(zhí)行過程

    Spring-Integration基于Spring,在應(yīng)用程序中啟用了輕量級(jí)消息傳遞,并支持通過聲明式適配器與外部系統(tǒng)集成,今天主要是看個(gè)簡單的hello word進(jìn)來分析下整個(gè)執(zhí)行過程,感興趣的朋友一起看看吧
    2021-06-06
  • intellij idea14打包apk文件和查看sha1值

    intellij idea14打包apk文件和查看sha1值

    這篇文章主要為大家詳細(xì)介紹了intellij idea14打包apk文件和查看sha1值,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • MyBatis基礎(chǔ)支持DataSource實(shí)現(xiàn)源碼解析

    MyBatis基礎(chǔ)支持DataSource實(shí)現(xiàn)源碼解析

    這篇文章主要為大家介紹了MyBatis基礎(chǔ)支持DataSource實(shí)現(xiàn)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Java數(shù)據(jù)類型超詳細(xì)示例講解

    Java數(shù)據(jù)類型超詳細(xì)示例講解

    Java程序中要求參與的計(jì)算的數(shù)據(jù),必須要保證數(shù)據(jù)類型的一致性,如果數(shù)據(jù)類型不一致將發(fā)生類型的轉(zhuǎn)換。本文將通過示例詳細(xì)說說Java中數(shù)據(jù)類型的轉(zhuǎn)換,感興趣的可以了解一下
    2022-11-11
  • SpringCloud配置刷新原理解析

    SpringCloud配置刷新原理解析

    這篇文章主要介紹了SpringCloud之配置刷新的原理,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05
  • Java技能點(diǎn)之SimpleDateFormat進(jìn)行日期格式化問題

    Java技能點(diǎn)之SimpleDateFormat進(jìn)行日期格式化問題

    這篇文章主要介紹了Java技能點(diǎn)之SimpleDateFormat進(jìn)行日期格式化問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 解讀Spring配置文件中的property標(biāo)簽中的屬性

    解讀Spring配置文件中的property標(biāo)簽中的屬性

    這篇文章主要介紹了Spring配置文件中的property標(biāo)簽中的屬性,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 使用java生成json時(shí)產(chǎn)生棧溢出錯(cuò)誤問題及解決方案

    使用java生成json時(shí)產(chǎn)生棧溢出錯(cuò)誤問題及解決方案

    這篇文章主要介紹了使用java生成json時(shí)產(chǎn)生棧溢出錯(cuò)誤問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • SpringBoot單元測(cè)試使用@Test沒有run方法的解決方案

    SpringBoot單元測(cè)試使用@Test沒有run方法的解決方案

    這篇文章主要介紹了SpringBoot單元測(cè)試使用@Test沒有run方法的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java運(yùn)行時(shí)數(shù)據(jù)區(qū)域和類結(jié)構(gòu)詳解

    java運(yùn)行時(shí)數(shù)據(jù)區(qū)域和類結(jié)構(gòu)詳解

    這篇文章主要介紹了java運(yùn)行時(shí)數(shù)據(jù)區(qū)域和類結(jié)構(gòu),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評(píng)論