SpringSecurity登录认证流程及源码分析

目录

一 作用

二 流程及源码分析 


一 作用

spring security作为spring家族中的一员,它的主要作用有两个,分别是认证和授权。

我们以前在实现登录功能的时候,前端会传来用户名和密码,然后我们根据前端传来的数据从用户表中的数据进行比较,从而实现用户登录。

而springSecurity的功能也有登录认证,并且它在登录认证成功后,会生成一个认证对象,当登录成功后再发送其他请求,就会根据这个认证对象来判断当前用户是否已经登录。

二 流程及源码分析 

在使用springSecurity之前,你还需要导入它的依赖坐标,只要导入了依赖,它就会自动生效。

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

① 用户输入用户名和密码以及验证码访问登录接口:

登录其实也是一个请求,所以也会被springsecurity拦截,但是因为你没有登录,就没有他的认证对象,它就不会让你访问这个接口,所以开始之前还需要在spring security的配置类中放行登录请求。(配置类的代码最后会统一给)

放行登录亲请求:

② 调用逻辑业务service层,完成验证。

package com.fs.system.service.ipml;

import cn.hutool.core.convert.Convert;
import com.fs.common.constant.CacheConstants;
import com.fs.common.constant.UserConstants;
import com.fs.common.core.pojo.SysUser;
import com.fs.common.core.vo.LoginUser;
import com.fs.common.enums.UserStatus;
import com.fs.common.exception.ServiceException;
import com.fs.common.exception.user.BlackListException;
import com.fs.common.exception.user.CaptchaException;
import com.fs.common.exception.user.UserNotExistsException;
import com.fs.common.exception.user.UserPasswordNotMatchException;
import com.fs.common.util.DateUtils;
import com.fs.common.util.RedisCache;
import com.fs.common.util.ip.IpUtils;
import com.fs.system.security.UserDetailsServiceImpl;
import com.fs.system.service.ISysConfigService;
import com.fs.system.service.ISysLoginService;
import com.fs.system.service.ISysUserService;
import com.mysql.cj.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
public class ISysLoginServiceImpl implements ISysLoginService {
    @Autowired
    private ISysUserService sysUserService ;  //进行用户信息校验,包括查询该用户是否存在

    @Autowired
    private SysPasswordService passwordService ;  //密码校验,包括密码输入的正确性已经输入密码的次数

    @Autowired
    private ISysConfigService sysConfigService ; //判断验证码功能有没有开启

    @Autowired
    private RedisCache redisCache ; //用于操作缓存中的数据

    @Autowired
    private TokenService tokenService ; //对token的操作

    @Autowired
    private UserDetailsServiceImpl userDetailsService ; //用来获取LoginUser对象

    @Autowired
    private AuthenticationManager authenticationManager ; //用于获取认证
    /** 登录验证 */
    @Override
    public String login(String username, String password, String code, String uuid) {
//        1.验证码验证码
        validateCaptcha(username , code , uuid);
        System.out.println("验证码校验完成...");
//        2.参数校验
        loginCheck(username , password) ;
        3.根据用户名查询用户
//        SysUser sysUser = sysUserService.selectUserByUserName(username);

//        检验密码
//        passwordService.validate(sysUser , password);  //通过Security帮我们进行处理,不需要自己校验了


//        创建token
//        //先创建一个LoginUser对象,因为返回的的是LoginUser对象
//        LoginUser loginUser = new LoginUser();
//        loginUser.setUserId(sysUser.getUserId());
//        loginUser.setUser(sysUser);

        //        返回一个认证对象
        Authentication authentication = null;
        try{
            //创建一个Authentication认证对象,  属性: authenticated =false, 没有被认证
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            //返回一个认证对象:  被认证认证对象
            authentication = authenticationManager.authenticate(authRequest); //这个认证对象就是一个登录的认证器

        }catch (Exception e){
            throw new  ServiceException("用户不存在或者是密码错误");
        }

        //调用tokenService创建token
        //里面已经给LoginUser赋值token了,不过这里面的token是一个uuid,redis存的是loginUser,LoginUser里面的token又是一个uuid?
        String token = tokenService.createToken((LoginUser) userDetailsService.loadUserByUsername(username));
//        修改登陆时间和登录ip
        LoginUser loginUser= (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
//        返回token给前端(token里面存放着登录用户的信息,)
        System.out.println("token:=========>"+token);
        return token;
    }

    /** 验证码验证码 */
    @Override
    public void validateCaptcha(String username, String code, String uuid) {
        /**
         * code是前端传来的验证码答案,uuid是验证码缓存的key
         */
//        先判断有没有开启验证码功能
        boolean captchaEnabled = sysConfigService.selectCaptchaEnabled();
        if (!captchaEnabled) throw new ServiceException("验证码功能没有开启");
//        然后根据key去查询缓存中的value,判断value和输入的答案是否正确
        String value = redisCache.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + uuid);
//        再将从缓存中拿到的value和code比对
        if (!value.equals(code)){
            throw new CaptchaException();
        }
    }


    /**  记录登录信息 :  */
    @Override
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUserService.updateUserProfile(sysUser);
    }

    /**  登录前置校验(对请求参数的校验)  */
    private void loginCheck(String username , String password){
//        非空校验
        if (Objects.isNull(username)||Objects.isNull(password)){
            throw new UserNotExistsException() ;
        }
//        长度校验
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH){
            throw new UserPasswordNotMatchException();
        }

        //用户名如果不在指定范围内
        if (username.length()<UserConstants.USERNAME_MIN_LENGTH||username.length()>UserConstants.USERNAME_MAX_LENGTH){
            throw new UserPasswordNotMatchException() ;
        }

        // IP黑名单校验
        //todo  这个地方调用selectConfigByKey这个方法,但是这个数据库里面根本没有记录黑名单的列
        String blackStr = sysConfigService.selectConfigByKey("sys.login.blackIPList");
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
        {
            throw new BlackListException();
        }
    }
}

 

③ 获取认证对象

我们需要调用spring security中的方法来获取一个认证对象,它会经过一系列的认证,只有最后用户的信息认证成功后才会生成一个认证对象,这说明用户认证成功,否则则说明这个用户认证失败。

 

④ 源码分析

那么我们就从这里作为入口,去看看springsecurity的源码是如何实现用户的账号信息以及密码校验的。

1.进入anthenticate方法后,我们发现这个是一个接口的抽象方法:

2.既然是接口,那我们就找到它的默认实现类ProviderManager,并且找到这个实现的方法:

3.那么我们继续看这个方法,这个方法的核心就是调用登录认证器的authenticate()方法:

 
 

4.我们现在知道这里主要就是调用了登录认证器的authenticate方法,那么我们就进这个方法看看里面实现了什么。最后发现这个方法也是一个接口的抽象方法:

5.然后我们找到它的实现类AbstractUserDetailsAuthenticationProvider,并且找到对应的方法:

6.我们找到实现方法authenticate后,发现它主要进行两步操作,先从缓存中获取到这个用户,如果是null,那么就调用etrieveUser()方法,而第一次登录里面肯什么都没有,所以是null,那么主要就是调用etrieveUser()方法:

7.那么不用多说,直接进入这个方法。但是发现它是一个抽象方法,那么我们肯定就是找到它的实现方法,去看里面的实现逻辑:

8.找到它的实现方法,这就已经到尾了,不过我们还记得一开时我们需要返回的值就是一个用户信息对象,所以这里也是找到了我们心心念念的 loadUserByUsername(username)方法:

9.那么我们肯定就进入这个方法去看看,发现它是接口 UserDetailsService的方法。

10.既然如此,我们只需要实现这个接口重写loadUserByUsername方法,然后从数据路根据用户名查询到用户信息,然后封装成一个loginUser对象,并且对这个用户的基本信息进行一个校验,没问题后就可以返回了,到这里根据用户名查找用户这个验证已经完成了。(不过需要注意,因为这个方法返回的是一个UserDetails,所以loginUser对象需要实现或者继承它才能作为该对象返回loginUser对象)

package com.fs.system.security;

import cn.hutool.core.util.ObjectUtil;
import com.fs.common.core.pojo.SysUser;
import com.fs.common.core.vo.LoginUser;
import com.fs.common.enums.UserStatus;
import com.fs.common.exception.ServiceException;
import com.fs.common.exception.user.UserNotExistsException;
import com.fs.system.mapper.SysUserMapper;
import com.fs.system.service.ipml.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.Collections;
import java.util.Objects;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private SysUserMapper userMapper ;
    @Autowired
    private TokenService tokenService ;
    @Override
    public UserDetails  loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("username:"+username);
//        从数据库查询用户信息
        SysUser sysUser = userMapper.selectUserByUserName(username);
        System.out.println("查询到用户信息:"+sysUser);

        //验证用户是否存在
        if (Objects.isNull(sysUser)){
            System.out.println("用户不存在");
            throw new UserNotExistsException() ;
        }
//        是否禁用
        if (sysUser.getStatus().equals(UserStatus.DISABLE)){
            throw  new ServiceException("用户已封禁") ;
        }
//        是否删除
        if (sysUser.getDelFlag()== UserStatus.DELETED.getCode()){
            throw new ServiceException("账号已经被删除");
        }

//        创建LoginUser对象
        LoginUser loginUser = creatLoginUser(sysUser);
//        创建token
        tokenService.createToken(loginUser);
        return loginUser ;
    }

    public LoginUser creatLoginUser(SysUser sysUser){
        //先创建一个LoginUser对象,因为返回的的是LoginUser对象
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(sysUser.getUserId());
        loginUser.setUser(sysUser);
        System.out.println("成功查询user对象并且返回:"+loginUser);
        return loginUser ;
    }
}

上面只是完成了用户名查到用户的功能,既然已经查询到用户的信息了,说明也就知道了用户的真实密码,那么我接下来就需要把用户输入的密码和真实密码做对比,所以我们继续回到DaoAuthenticationProvider类中。

在这里的 createSuccessAuthentication()方法中,我们成功看见了密码比对的方法:

我们直接找到源头,发现这个加密方法是一个PasswordEncoder接口的抽象方法,里面主要两个方法,分别用于对前端输入的密码加密,还有把加密后的密码和用户信息中的密码进行比对。

所以,我们要实现自定义的加密以及对密码进行比对,我们只需要实现这个接口,同时完成这个两个方法的实现就可以了:

package com.fs.system.security;

import cn.hutool.core.convert.Convert;
import com.fs.common.util.sign.PasswordUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @author suke
 * @version 1.0
 * @title MyPasswordEncoder
 * @description  自定义的密码编码
 * @create 2024/7/25 10:58
 */
@Component
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {

        return PasswordUtils.generate(Convert.toStr(rawPassword));
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return PasswordUtils.verify(Convert.toStr(rawPassword),encodedPassword);
    }
}
  
PasswordUtils是我们用于密码的加密和比对的一个工具类,我们使用的是md5加密,工具类代码如下:
package com.fs.common.util.sign;

import java.security.MessageDigest;
import java.util.Random;

/**
 * MD5加盐加密
 */    
public class PasswordUtils {
    /**
     * 生成含有 随机盐的密码
     */
    public static String generate(String password) {
        Random r = new Random();
        StringBuilder sb = new StringBuilder(16);
        sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
        int len = sb.length();
        if (len < 16) {  //不够16位,前面补0
            for (int i = 0; i < 16 - len; i++) {
                sb.append("0");
            }
        }

        String salt = sb.toString();
        password = md5Hex(password + salt); //32位的16进制
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return new String(cs);
    }
    /**
     * 校验密码是否正确
     */
    public static boolean verify(String password, String md5) {
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md5.charAt(i);
            cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
            cs2[i / 3] = md5.charAt(i + 1);
        }
        String salt = new String(cs2);
        return md5Hex(password + salt).equals(new String(cs1));
    }
    /**
     * 获取十六进制字符串形式的MD5摘要
     */
    public static String md5Hex(String src) {
        try {
            return Md5Utils.hash(src);
        } catch (Exception e) {
            return null;
        }
    }

    public static void main(String[] args) {
        System.out.println(generate("123456"));
        //System.out.println(verify("123456", "02dd65660724d38816641b3a98409fa2080401b489c9ff42"));
    }
}

最后在这里,这个校验过程就完成了,最后会成功创建一个认证对象。

随后,我们只需要创建一个token,返回给前端就欧克了。

这里附上token创建的代码:

package com.fs.system.service.ipml;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fs.common.constant.CacheConstants;
import com.fs.common.constant.Constants;
import com.fs.common.core.vo.LoginUser;
import com.fs.common.util.RedisCache;
import com.fs.common.util.ServletUtils;
import com.fs.common.util.ip.AddressUtils;
import com.fs.common.util.ip.IpUtils;
import com.fs.system.config.TokenProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

/**
 * token验证处理
 */
@Service
public class TokenService {
    @Autowired
    private TokenProperties tokenProperties;

    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;

    @Autowired
    private RedisCache redisCache;

    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser(HttpServletRequest request){
        // 获取请求携带的令牌
        String token = getToken(request);
        if (StringUtils.isNotEmpty(token))
        {
            try
            {
                Claims claims = parseToken(token);
                // 解析对应的权限以及用户信息
                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                String userKey = getTokenKey(uuid);
                LoginUser user = redisCache.getCacheObject(userKey);
                return user;
            }
            catch (Exception e)
            {
            }
        }
        return null;
    }

    /**
     * 设置用户身份信息
     */
    public void setLoginUser(LoginUser loginUser){
        if (Objects.nonNull(loginUser) && StrUtil.isNotEmpty(loginUser.getToken()))
        {
            refreshToken(loginUser);
        }
    }

    /**
     * 删除用户身份信息
     */
    public void delLoginUser(String token){
        if (StringUtils.isNotEmpty(token)){
            String userKey = getTokenKey(token);
            redisCache.deleteObject(userKey);
        }
    }

    /**
     * 创建令牌
     *
     * @param loginUser 用户信息
     * @return 令牌
     */
    public String createToken(LoginUser loginUser){
        String token = UUID.randomUUID(false).toString(true);
        loginUser.setToken(token);
        setUserAgent(loginUser);
        refreshToken(loginUser);

        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.LOGIN_USER_KEY, token);
        return createToken(claims);
    }

    /**
     * 验证令牌有效期,相差不足20分钟,自动刷新缓存
     *
     * @param loginUser
     * @return 令牌
     */
    public void verifyToken(LoginUser loginUser){
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
        {
            refreshToken(loginUser);
        }
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser){
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + tokenProperties.getExpireTime() * MILLIS_MINUTE);
        // 根据uuid将loginUser缓存
        String userKey = getTokenKey(loginUser.getToken());
        redisCache.setCacheObject(userKey, loginUser, tokenProperties.getExpireTime(), TimeUnit.MINUTES);
    }

    /**
     * 设置用户代理信息
     *
     * @param loginUser 登录信息
     */
    public void setUserAgent(LoginUser loginUser){
        UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
        String ip = IpUtils.getIpAddr();
        loginUser.setIpaddr(ip);
        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOs().getName());
    }

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String createToken(Map<String, Object> claims){
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, tokenProperties.getSecret()).compact();
        return token;
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token){
        return Jwts.parser()
                .setSigningKey(tokenProperties.getSecret())
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 从令牌中获取用户名
     *
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token){
        Claims claims = parseToken(token);
        return claims.getSubject();
    }

    /**
     * 获取请求token
     *
     * @param request
     * @return token
     */
    private String getToken(HttpServletRequest request){
        String token = request.getHeader(tokenProperties.getHeader());
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)){
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }

    private String getTokenKey(String uuid){
        return CacheConstants.LOGIN_TOKEN_KEY + uuid;
    }
}

 最后再附上spring security配置类的完成代码:

package com.fs.system.config;

import com.fs.common.util.RedisCache;
import com.fs.system.security.JwtAuthenticationTokenFilter;
import com.fs.system.security.MyDaoAuthenticationProvider;
import com.fs.system.security.MyPasswordEncoder;
import com.fs.system.security.TokenAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.config.BeanIds;
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.builders.WebSecurity;
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.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;

/**
 * @author suke
 * @version 1.0
 * @title SpringSecurityConfiguration
 * @description  springSecurity的自定义配置类
 * @create 2024/7/25 10:14
 */
@Configuration
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
//    @Qualifier("userDetailsServiceImpl")
    private UserDetailsService userDetailsService;

    @Autowired
    private RedisCache redisCache ;

    @Autowired
    private SysPasswordProperties  passwordProperties ;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter ;

    @Autowired
    private CorsFilter corsFilter;

    @Autowired
    private TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint;

//    @Autowired
//    private LogoutSuccessHandlerImpl logoutSuccessHandler;
    //对密码进行加密    密码校验
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new MyPasswordEncoder() ;
    }
    //修改用户名,密码
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("进入配置类...");

        //使用MyDaoAuthenticationProvider
        auth.authenticationProvider(new MyDaoAuthenticationProvider(userDetailsService,redisCache,passwordEncoder(),passwordProperties));


    }
修改用户名,密码
//@Override
//protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//    //使用MyDaoAuthenticationProvider
//    auth.authenticationProvider(new MyDaoAuthenticationProvider());
//}

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // CSRF禁用,因为不使用session
                .csrf().disable()
                // 禁用HTTP响应标头
                .headers().cacheControl().disable().and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                .antMatchers("/login","/getRouters", "/captchaImage").permitAll()
                // 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable();


        //添加过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        //添加跨域过滤器
        http.addFilterBefore(corsFilter,JwtAuthenticationTokenFilter.class);

        //配置认证失败的入口
        http.exceptionHandling().authenticationEntryPoint(tokenAuthenticationEntryPoint);
//
//        //配置注销
//        http.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
    }


}
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值