springSecurity基于springboot鉴权

gradle引入

implementation 'org.springframework.boot:spring-boot-starter-security'

WebSecurityConfiguration 拦截请求鉴权

import lombok.extern.slf4j.Slf4j;
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.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;

import javax.annotation.Resource;

@Slf4j
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    

    @Autowired
    private XiaozuAuthenticationUserDetailsService authenticationUserDetailsService;
    @Resource
    private UserInfoService userInfoService;
   

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
    
    	//对/api下所有请求拦截鉴权
        http.antMatcher(CommonConstant.HttpPathNamespace.API+"/**")
                .csrf().disable()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 对于获取token的rest api要允许匿名访问
//                .antMatchers(CommonConstant.HttpPathNamespace.INNER+"/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and().exceptionHandling().authenticationEntryPoint(new Http203AuthenticationEntryPoint());

        http.addFilterAfter(new XiaozuAuthCodeAuthenticationFilter(
                userInfoService), UsernamePasswordAuthenticationFilter.class);
        // 禁用缓存
        http.headers().cacheControl();
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
    
    
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
    
        PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
        provider.setPreAuthenticatedUserDetailsService(authenticationUserDetailsService);
        auth.authenticationProvider(provider);
    }

    @Bean
    public XiaozuAuthenticationUserDetailsService authenticationUserDetailsService() {
    
    
        return new XiaozuAuthenticationUserDetailsService();
    }
}

XiaozuAuthCodeAuthenticationFilter处理鉴权逻辑

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;

@Slf4j
public class XiaozuAuthCodeAuthenticationFilter extends OncePerRequestFilter {
    
    

    private UserInfoService userInfoService;
    public XiaozuAuthCodeAuthenticationFilter() {
    
    
    }

    public XiaozuAuthCodeAuthenticationFilter(UserInfoService userInfoService) {
    
    
        this.userInfoService = userInfoService;
    }


    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain) throws ServletException, IOException {
    
    

        //1、用户首次访问,客户端没有authcode(后端作为token进行存储redis),则返回203,表示没有授权头
        //2、若是支付宝或者微信,则客户端请求支付宝或者微信api生成authCode;若不是,则走另外一套鉴权逻辑了(鉴权成功后,token在后端生成返回给前端)
        //3、有authCode(token)信息后,则查询是否存在该token,若存在,则鉴权通过;若不存在,则进行三方鉴权,然后处理用户相关信息
        String appName = getAppName(request);
        if (StringUtils.isBlank(appName)) {
    
    
            authFailResp(response);
            log.error("用户鉴权失败appName为空:{}",request);
            return;
        }
        EnumAppName enumAppName = EnumAppName.valueOf(appName);
        String authCode = getAuthCode(request, enumAppName);
     

        if (!ObjectUtils.isEmpty(authCode)) {
    
    
            String username = StringUtils.EMPTY;
            if (!userCacheService.checkAuthToken(authCode,appName)) {
    
    
                // token在redis中不存在,则需要进行存储
                // 1、使用authCode进行鉴权,通过第三方获取用户信息
                // 2、鉴权通过后,拿到用户信息,则进行用户处理(在MySQL中判断用户是否存在,若存在,则返回useId,若不存在,则生成user)
                username = dealWithAuth(enumAppName, channel, authCode, appName);
                if (StringUtils.isBlank(username)) {
    
    
                    authFailResp(response);
                    log.error("用户鉴权失败appName:{},channel:{}", appName, channel);
                    return;
                }
                // 3、将用户token,userId存储在redis中
                authCode = DigestUtils.md5DigestAsHex(username.getBytes());
                userCacheService.setAuthToken(authCode, username,appName);
            } else {
    
    
                username = userCacheService.getUserName(authCode,appName);
            }
         
            // security容器中放入用户信息
            PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(username, authCode);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            response.setHeader(CommonConstant.HttpHeader.TOKEN, authCode);
        }
        filterChain.doFilter(request, response);
    }

    private void authFailResp(HttpServletResponse response) throws ServletException, IOException {
    
    
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(HttpStatus.NON_AUTHORITATIVE_INFORMATION.value());
        PrintWriter out = response.getWriter();
        JSONObject res = new JSONObject();
        res.put("msg", OperationStatus.AUTH_FAIL.getName());
        res.put("code", OperationStatus.AUTH_FAIL.getType());
        out.append(res.toString());
    }

    private String dealWithAuth() {
    
    
       		//处理鉴权逻辑 返回用户唯一标识token
       		return "";
        }
    }
}

XiaozuAuthenticationUserDetailsService

import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;

import java.util.Collections;

@Component
public class XiaozuAuthenticationUserDetailsService implements
        AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
    
    

    @Override
    public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token) throws UsernameNotFoundException {
    
    
        String username = (String) token.getPrincipal();
        String accessToken = (String) token.getCredentials();
        return new User(username, accessToken, Collections.emptyList());
    }
}

Http203AuthenticationEntryPoint

import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Http203AuthenticationEntryPoint implements AuthenticationEntryPoint {
    
    

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException, ServletException {
    
    
        response.sendError(HttpStatus.NON_AUTHORITATIVE_INFORMATION.value(), authException.getMessage());
    }
}

猜你喜欢

转载自blog.csdn.net/My_Way666/article/details/108258302