Spring Security配置(包含WebSecurityConfigurerAdapter过时问题)

Spring Security配置(包含WebSecurityConfigurerAdapter过时问题)

  • pom.xml文件引入以下依赖
    <!--spring security-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
                <version>2.7.0</version>
            </dependency>
            <!--JWT-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.9.1</version>
            </dependency>
            <!--redis-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <!-- 排除lettuce包,使用jedis代替-->
                <exclusions>
                    <exclusion>
                        <groupId>io.lettuce</groupId>
                        <artifactId>lettuce-core</artifactId>
                    </exclusion>
                </exclusions>
                <version>2.7.0</version>
            </dependency>
            <!--jedis-->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>3.7.1</version>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.29</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.2.9</version>
            </dependency>
  • application.yml文件配置
    # Tomcat
    server:
      port: 8088
      tomcat:
        uri-encoding: UTF-8
        connection-timeout: 5000ms
        threads:
          max: 1000
          min-spare: 30
      servlet:
        context-path: /gremlin
        encoding:
          charset: UTF-8
    # spring配置
    spring:
      mvc:
        pathmatch:
          matching-strategy: ant_path_matcher
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/forum?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
          username: root
          password: root
      redis:
        database: 0  # Redis数据库索引(默认为0)
        host: 127.0.0.1 # Redis服务器地址
        port: 6379 # Redis服务器连接端口
        jedis:
          pool:
            max-active: 8  # 连接池最大连接数(使用负值表示没有限制) 默认 8
            max-wait: -1   # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
            max-idle: 8    # 连接池中的最大空闲连接 默认 8
            min-idle: 0    # 连接池中的最小空闲连接 默认 0
  • security配置 (编写SecurityConfig配置文件(WebSecurityConfigurerAdapter过时代替配置在文末))
    package com.gremlin.config;
    
    import com.gremlin.common.utils.RedisUtils;
    import com.gremlin.log.service.LogService;
    import com.gremlin.power.mapper.PowerManagerMapper;
    import com.gremlin.power.service.PowerManagerService;
    import com.gremlin.security.fifter.JwtAuthenticationTokenFilter;
    import com.gremlin.security.fifter.TokenLoginFilter;
    import com.gremlin.security.handler.AjaxAccessDeniedHandler;
    import com.gremlin.security.handler.AjaxAuthenticationEntryPoint;
    import com.gremlin.security.handler.AjaxLogoutSuccessHandler;
    import com.gremlin.security.service.MyUserDetailsServiceImpl;
    import com.gremlin.security.strategy.CustomizeSessionInformationExpiredStrategy;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    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.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    /**
     * Description: security配置类
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        /**
         * 注销成功返回的 JSON 格式数据给前端
         */
        @Autowired
        private AjaxLogoutSuccessHandler logoutSuccessHandler;
        /**
         * 无权访问 JSON 格式的数据
         */
        @Autowired
        private AjaxAccessDeniedHandler ajaxAccessDeniedHandler;
        @Autowired
        private AjaxAuthenticationEntryPoint authenticationEntryPoint;
        @Autowired
        private CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;
        @Autowired
        private JwtAuthenticationTokenFilter tokenAuthenticationFilter;
        @Autowired
        private RedisUtils redisUtils;
        @Autowired
        private LogService logService;
        @Autowired
        private PowerManagerMapper powerManagerMapper;
        @Autowired
        private MyUserDetailsServiceImpl userDetailsService;
        @Autowired
        private PowerManagerService powerManagerService;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
            http.cors().and().csrf().disable();
            http.httpBasic()
                    .authenticationEntryPoint(authenticationEntryPoint)
                    .and()
                    .authorizeRequests()
                    //自定义放行接口
                    .antMatchers(
                            "/swagger**/**",
                            "/swagger-ui.html",
                            "/swagger-resources/**",
                            "/webjars/**",
                            "/v3/**"
                    ).permitAll()
    
                    .anyRequest()
                    .authenticated()
                    .and().logout().logoutUrl("/logout")
                    //登出处理
                    .logoutSuccessHandler(logoutSuccessHandler)
                    //添加关于自定义的认证过滤器和自定义的授权过滤器
                    .and()
                    .logout().permitAll()//注销行为任意访问
                    //会话管理
                    .and().sessionManagement()
                    //同一账号同时登录最大用户数
                    .maximumSessions(1)
                    //会话信息过期策略会话信息过期策略(账号被挤下线)
                    .expiredSessionStrategy(sessionInformationExpiredStrategy);
    
            //自定义权限拒绝处理类
            // 无权访问 JSON 格式的数据
            http.exceptionHandling().accessDeniedHandler(ajaxAccessDeniedHandler);
            // 登录验证
            http.addFilter(new TokenLoginFilter(authenticationManager(),redisUtils,logService,powerManagerMapper)).httpBasic();
            // JWT Filter
            http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/css/**", "/js/**", "/index.html", "/img/**", "/fonts/**", "/favicon.ico", "/verifyCode");
        }
    
        @Bean
        public BCryptPasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    }
  • 编写UserDetailsService的实现类
    package com.gremlin.security.service;
    
    import com.gremlin.security.mapper.UserMapper;
    import com.gremlin.security.vo.MyUserDetails;
    import com.gremlin.security.vo.User;
    import com.gremlin.security.vo.req.ReqUser;
    import org.springframework.beans.factory.annotation.Autowired;
    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;
    
    /**
     * Description: 自定义的Service,实现于springSecurity框架的UserDetailsService
     * @author: gremlin
     * Date: 2022/6/10 13:02
     * @version: 1.0.0
     */
    @Service
    public class MyUserDetailsServiceImpl implements UserDetailsService {
    
        @Autowired
        private UserMapper userMapper;
        
        @Override
        public UserDetails loadUserByUsername(String loginUsername) throws UsernameNotFoundException {
            ReqUser reqUser = new ReqUser();
            reqUser.setLoginUsername(loginUsername);
            // 通过账户查询账户信息
            User userInfo = userMapper.getUserInfo(reqUser);
            if (null == userInfo){
                throw new UsernameNotFoundException("该用户不存在或被禁用请联系管理员");
            }
            String password = userInfo.getPassword();
            //找到该账号下面的权限
            return new MyUserDetails(loginUsername,password);
        }
    }
  • 编写token登录过滤器
    package com.gremlin.security.fifter;
    
    import com.alibaba.fastjson2.JSON;
    import com.alibaba.fastjson2.JSONObject;
    import com.gremlin.account.vo.req.ReqAccount;
    import com.gremlin.common.resp.ResponseResult;
    import com.gremlin.common.resp.ResultEnum;
    import com.gremlin.common.utils.AccessAddressUtils;
    import com.gremlin.common.utils.JwtTokenUtils;
    import com.gremlin.common.utils.RedisUtils;
    import com.gremlin.log.service.LogService;
    import com.gremlin.power.mapper.PowerManagerMapper;
    import com.gremlin.power.vo.resp.RespRole;
    import com.gremlin.security.vo.MyUserDetails;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.LockedException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.nio.charset.StandardCharsets;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Description: token登录过滤器
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Slf4j
    public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    
        private final RedisUtils redisUtil;
        private final AuthenticationManager authenticationManager;
        private final LogService logService;
        private final PowerManagerMapper powerManagerMapper;
    
        public TokenLoginFilter(AuthenticationManager authenticationManager, RedisUtils redisUtil,
                                LogService logService,PowerManagerMapper powerManagerMapper) {
            this.authenticationManager = authenticationManager;
            this.redisUtil = redisUtil;
            this.logService = logService;
            this.powerManagerMapper = powerManagerMapper;
        }
    
        /**
         * 通过前端传来的json数据(用户名 密码),解析成我们的java对象,最终得到用户名和密码去进行认证
         */
        @Override
        public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
                throws AuthenticationException {
            System.out.println(2);
            //只允许post请求
            if ("POST".equals(req.getMethod())) {
                // 获取请求体
                String body = getBody(req);
                // 转换为json格式
                JSONObject jsonObject = JSON.parseObject(body);
                String username = jsonObject.getString("loginUsername");
                String password = jsonObject.getString("password");
                // 获取ip地址
                String ip = AccessAddressUtils.getIpAddress(req);
    
                if (username == null) {
                    username = "";
                }
                if (password == null) {
                    password = "";
                }
                username = username.trim();
                UsernamePasswordAuthenticationToken authRequest =
                        new UsernamePasswordAuthenticationToken(username, password);
    
                //插入用户登录成功日志
                logService.insertLog(ip, "1", "登入", username);
                return authenticationManager.authenticate(authRequest);
            }
            return null;
        }
    
        /**
         * 若认证成功,根据用户名生成token返回给前端。并以用户名为key,权限列表为value的形式存入redis缓存中
         */
        @Override
        protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                                Authentication auth) throws IOException {
            System.out.println(4);
            Map<String, Object> map = new HashMap<>();
            // 获取IP地址
            String ip = AccessAddressUtils.getIpAddress(req);
            map.put("ip", ip);
            // 获取当前用户信息
            MyUserDetails userDetails = (MyUserDetails) auth.getPrincipal();
            // 通过jwt生成jwtToken
            String jwtToken = JwtTokenUtils.generateToken(userDetails.getUsername(),map);
            // 将token赋值到用户对象类
            userDetails.setToken(jwtToken);
    
            // 通过用户名称查询用户的角色
            ReqAccount reqAccount = new ReqAccount();
            reqAccount.setLoginUsername(userDetails.getUsername());
            RespRole respRole = new RespRole();
            respRole = powerManagerMapper.queryRoleByUsername(reqAccount);
            map.put("juese",respRole);
            //获取请求的ip地址
            redisUtil.setTokenRefresh(userDetails.getUsername(), userDetails.getToken(), ip);
    
            log.info("用户{}登录成功,信息已保存至redis", userDetails.getUsername());
            res.setHeader("Content-type", "application/json;charset=UTF-8");
            map.put("token", jwtToken);
            redisUtil.set(userDetails.getUsername()+"token",jwtToken);
            res.getWriter().write(JSON.toJSONString(ResponseResult.success(map, ResultEnum.SUCCESS.getCode(), ResultEnum.USER_LOGIN_SUCCESS.getMessage())));
        }
    
        /**
         * 登录失败 若认证失败,则返回错误信息给前端
         */
        @Override
        protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                                  AuthenticationException e) throws IOException {
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            if (e instanceof UsernameNotFoundException) {
                response.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.USER_NOT_FIND.getMessage(), ResultEnum.USER_NOT_FIND.getCode())));
            } else if (e instanceof BadCredentialsException) {
                response.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.USER_LOGIN_FAILED.getMessage(), ResultEnum.USER_LOGIN_FAILED.getCode())));
            } else if (e instanceof LockedException) {
                response.getWriter().write(JSON.toJSONString(ResponseResult.failed("用户已被锁定", 207)));
            }else {
                response.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.USER_LOGIN_FAILED.getMessage(), ResultEnum.USER_LOGIN_FAILED.getCode())));
            }
        }
    
        /**
         * 获取请求Body
         */
        public String getBody(HttpServletRequest request) {
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = null;
            BufferedReader reader = null;
            try {
                inputStream = request.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();
        }
    }
  • 编写token认证过滤器
    package com.gremlin.security.fifter;
    
    import com.alibaba.fastjson2.JSON;
    import com.gremlin.common.resp.ResponseResult;
    import com.gremlin.common.resp.ResultEnum;
    import com.gremlin.common.utils.CollectionUtil;
    import com.gremlin.common.utils.DateUtil;
    import com.gremlin.common.utils.JwtTokenUtils;
    import com.gremlin.common.utils.RedisUtils;
    import com.gremlin.security.service.MyUserDetailsServiceImpl;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.ResponseBody;
    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.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Description: token认证过滤器
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Component
    @Slf4j
    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    
        @Autowired
        private MyUserDetailsServiceImpl userDetailsService;
        @Autowired
        private RedisUtils redisUtil;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            System.out.println(1);
            String authToken = request.getHeader("token");
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            if (null != authToken) {
                //判断token是否有效
                if (!JwtTokenUtils.isTokenExpired(authToken)) {
                    response.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.LOGIN_IS_OVERDUE.getMessage(), ResultEnum.LOGIN_IS_OVERDUE.getCode())));
                }
                // 通过token获取用户名
                String username = JwtTokenUtils.parseToken(authToken);
                if (StringUtils.isBlank(username)) {
                    return;
                }
                String ip = CollectionUtil.getMapValue(JwtTokenUtils.getClaims(authToken), "ip");
                //判断redis是否有保存
                if (redisUtil.hasKey(username)) {
                    //有效时间
                    String expirationTime = redisUtil.hasGet(username, "expirationTime").toString();
                    if (JwtTokenUtils.isExpiration(expirationTime)) {
                        // token失效
                        //当前时间超过有效时间,用户登录失效
                        //获得redis中用户的token刷新时效
                        String tokenValidTime = (String) redisUtil.getTokenValidTimeByToken(username);
                        String currentTime = DateUtil.getTime();
                        //这个token已作废,加入黑名单
                        if (DateUtil.compareDate(currentTime, tokenValidTime) && !DateUtil.compareDate(tokenValidTime, expirationTime)) {
                            //超过有效期,不予刷新
                            log.info("{}已超过有效期,不予刷新", authToken);
                            response.getWriter().write(JSON.toJSONString(ResponseResult.success(null, ResultEnum.LOGIN_IS_OVERDUE.getCode(), ResultEnum.LOGIN_IS_OVERDUE.getMessage())));
                            return;
                        } else {
                            //仍在有效时间内,判断是否到达刷新时间,如果到达刷新时间
                            // (刷新时间判断方法为token时间-当前时间<=5min),刷新token否则不更新token
                            Date tokenTime = JwtTokenUtils.getTokenTime(authToken);
                            // 则刷新token,放入请求头中
                            String usernameByToken = (String) redisUtil.getUsernameByToken(username);
                            //更新username
                            username = usernameByToken;
                            //更新ip
                            ip = (String) redisUtil.getIpByToken(username);
                            //token中的时间与当前时间做对比,
                            if (DateUtil.compareDate(tokenTime, new Date())) {
                                Map<String, Object> map = new HashMap<>();
                                map.put("ip", ip);
                                String jwtToken = JwtTokenUtils.generateToken(usernameByToken,map);
                                redisUtil.setTokenRefresh(username, jwtToken, ip);
                                log.info("redis已删除旧token:{},新token:{}已更新redis", authToken, jwtToken);
                                //更新token,为了后面
                                authToken = jwtToken;
                            }
                            redisUtil.set(username + "token", authToken, 1200);
                        }
                    }
                } else {
                    log.info("{}redis登录信息不存在", username);
                    response.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.LOGIN_IS_OVERDUE.getMessage(), ResultEnum.LOGIN_IS_OVERDUE.getCode())));
                    return;
                }
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                    if (userDetails != null) {
                        UsernamePasswordAuthenticationToken authentication =
                                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        response.reset();
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
            }
            filterChain.doFilter(request, response);
        }
    }
  • 编写实现UserDetails的实体类
    package com.gremlin.security.vo;
    
    import io.swagger.annotations.ApiModelProperty;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import java.util.Collection;
    
    /**
     * Description: 自定义的实体类,实现于spring security框架的UserDetails
     * @author: gremlin
     * Date: 2022/6/10 13:06
     * @version: 1.0.0
     */
    public class MyUserDetails implements UserDetails {
    
        @ApiModelProperty(value = "用户账户")
        private String username;
        @ApiModelProperty(value = "用户密码")
        private String password;
        @ApiModelProperty(value = "用户token值")
        private String token;
    
        public MyUserDetails(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
    
        public void setToken(String token) {
            this.token = token;
        }
    
        public String getToken() {
            return token;
        }
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return null;
        }
    
        @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;
        }
    }
  • 编写无权访问响应类
    package com.gremlin.security.handler;
    
    import com.alibaba.fastjson2.JSON;
    import com.gremlin.common.resp.ResponseResult;
    import com.gremlin.common.resp.ResultEnum;
    import org.springframework.security.access.AccessDeniedException;
    import org.springframework.security.web.access.AccessDeniedHandler;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Description: 无权访问
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Component
    public class AjaxAccessDeniedHandler implements AccessDeniedHandler {
        @Override
        public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
            httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");
            httpServletResponse.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.USER_NO_ACCESS.getMessage(),ResultEnum.USER_NO_ACCESS.getCode())));
        }
    }
  • 编写token认证身份验证入口点
    package com.gremlin.security.handler;
    
    import com.alibaba.fastjson.JSON;
    import com.gremlin.common.resp.ResponseResult;
    import com.gremlin.common.resp.ResultEnum;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.AuthenticationEntryPoint;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Description: 用户未登录时返回给前端的数据 身份验证入口点
     * @author: gremlin
     * Date: 2022/6/10 17:24
     * @version: 1.0.0
     */
    @Component
    public class AjaxAuthenticationEntryPoint implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response,
                             AuthenticationException authException) throws IOException {
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.USER_NEED_AUTHORITIES.getMessage(),ResultEnum.USER_NEED_AUTHORITIES.getCode())));
        }
    }
  • 编写自定义处理注销成功的类
    package com.gremlin.security.handler;
    
    
    import com.alibaba.fastjson2.JSON;
    import com.gremlin.common.resp.ResponseResult;
    import com.gremlin.common.resp.ResultEnum;
    import com.gremlin.common.utils.JwtTokenUtils;
    import com.gremlin.common.utils.RedisUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Description: 自定义处理注销成功的类
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Component
    @Slf4j
    public class AjaxLogoutSuccessHandler implements LogoutSuccessHandler {
    
        @Autowired
        private RedisUtils redisUtil;
    
        @Override
        public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException {
            // 获取头部信息的token
            String authToken = req.getHeader("token");
            if (null != authToken) {
                String username = JwtTokenUtils.parseToken(authToken);
                // 清除redis里的token等其他值
                redisUtil.deleteKeys(username);
                log.info("用户登出成功!token:{}已从redis删除", authToken);
            }
            resp.setHeader("Content-type", "application/json;charset=UTF-8");
            resp.getWriter().write(JSON.toJSONString(ResponseResult.failed(ResultEnum.USER_LOGOUT_SUCCESS.getMessage(), ResultEnum.USER_LOGOUT_SUCCESS.getCode())));
        }
    }
  • 编写会话信息过期策略类
    package com.gremlin.security.strategy;
    
    import com.alibaba.fastjson2.JSON;
    import com.gremlin.common.resp.ResponseResult;
    import com.gremlin.common.resp.ResultEnum;
    import org.springframework.security.web.session.SessionInformationExpiredEvent;
    import org.springframework.security.web.session.SessionInformationExpiredStrategy;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Description: 会话信息过期策略
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Component
    public class CustomizeSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
        @Override
        public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException {
            HttpServletResponse httpServletResponse = sessionInformationExpiredEvent.getResponse();
            httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");
            httpServletResponse.getWriter().write(JSON.toJSONString(
                    ResponseResult.failed(ResultEnum.USER_NO_ACCESS.getMessage(),ResultEnum.USER_NO_ACCESS.getCode())));
    
        }
    }
  • 编写结果响应json返回类
    package com.gremlin.common.resp;
    
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.Serializable;
    
    /**
     * Description: 结果响应json返回类
     * @author: gremlin
     * Date: 2022/6/9 15:54
     * @version: 1.0.0
     */
    @Slf4j
    @Data
    public class ResponseResult<T>  implements Serializable {
    
        @ApiModelProperty(value = "返回数据")
        private T data;
        @ApiModelProperty(value = "返回信息")
        private String msg;
        @ApiModelProperty(value = "结果code")
        private Integer code;
        @ApiModelProperty(value = "是否成功")
        private Boolean isSuccess = true;
    
        public ResponseResult() {
        }
    
        /**
         * 成功
         */
        public ResponseResult(T data,Integer code, String msg) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
        /**
         * 成功
         */
        public ResponseResult(T data,Integer code, String msg,Boolean isSuccess) {
            this.code = code;
            this.msg = msg;
            this.data = data;
            this.isSuccess = isSuccess;
        }
    
        /**
         * 失败
         */
        public ResponseResult(String msg,Integer code) {
            this.code = code;
            this.msg = msg;
        }
        /**
         * 失败
         */
        public ResponseResult(String msg) {
            this.msg = msg;
        }
    
        /**
         * 方便静态调用(成功)
         */
        public static <T> ResponseResult<T> success(T data, Integer code, String msg) {
            return new ResponseResult<T>(data,code,msg);
        }
        /**
         * 方便静态调用(成功)
         */
        public static <T> ResponseResult<T> success(T data, Integer code, String msg,Boolean isSuccess) {
            return new ResponseResult<T>(data,code,msg,isSuccess);
        }
    
        /**
         * 方便静态调用(失败)
         */
        public static <T> ResponseResult<T> failed(String msg,Integer code) {
            return new ResponseResult<T>(msg,code);
        }
    
        /**
         * 方便静态调用(失败)
         */
        public static <T> ResponseResult<T> failed(String msg) {
            return new ResponseResult<T>(msg);
        }
    }
  • 编写结果code枚举类
    package com.gremlin.common.resp;
    
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Getter;
    
    /**
     * Description: 结果code枚举类
     * @author: gremlin
     * Date: 2022/6/9 16:13
     * @version: 1.0.0
     */
    @Getter
    public enum ResultEnum {
        /**
         * 请求成功
         */
        SUCCESS(200,"请求成功"),
        /**
         * 请求失败
         */
        FAILURE(102,"请求失败"),
        /**
         * 用户未登录
         */
        USER_NEED_AUTHORITIES(201,"用户未登录"),
        /**
         * 用户登录成功
         */
        USER_LOGIN_SUCCESS(203,"login success!"),
        /**
         * 用户账号或密码错误
         */
        USER_LOGIN_FAILED(202,"用户账号或密码错误"),
        /**
         * 用户不存在
         */
        USER_NOT_FIND(206,"该用户不存在或被禁用请联系管理员"),
        /**
         * 用户登出成功
         */
        USER_LOGOUT_SUCCESS(205,"登出成功!"),
        /**
         * 用户无权访问
         */
        USER_NO_ACCESS(301,"用户无权访问"),
        /**
         * 您的操作已超时,请重新登录
         */
        LOGIN_IS_OVERDUE(204,"您的操作已超时,请重新登录"),
        /**
         * 手机号码不正确
         */
        ERROR_PHONE(50001,"手机号码不正确"),
        /**
         * 邮箱地址不正确
         */
        ERROR_EMAIL(50002,"邮箱地址不正确"),
        /**
         * 验证码错误
         */
        ERROR_CODE(50003,"验证码错误"),
        /**
         * 邮件发送成功
         */
        SEND_EMAIL(205,"邮件发送成功!")
    
        ;
        @ApiModelProperty(value = "返回code")
        private final Integer code;
        @ApiModelProperty(value = "返回信息")
        private final String message;
    
        ResultEnum(Integer code, String message) {
            this.code = code;
            this.message = message;
        }
    }
  • 编写工具类ip地址获取工具类
    package com.gremlin.common.utils;
    
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * Description: ip地址获取工具类
     * @author: gremlin
     * Date: 2022/6/10 15:11
     * @version: 1.0.0
     */
    @Component
    public class AccessAddressUtils {
        /**
         * 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
         * 参考文章: http://developer.51cto.com/art/201111/305181.htm
         *
         * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
         * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
         *
         * 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,
         * 192.168.1.100
         *
         * 用户真实IP为: 192.168.1.110
         */
        public static String getIpAddress(HttpServletRequest request) {
            String ip = request.getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }
    }
  • 编写工具类日期处理工具类
    package com.gremlin.common.utils;
    
    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.GregorianCalendar;
    
    /**
     * Description: 日期处理工具类
     * @author: gremlin
     * Date: 2022/6/10 15:17
     * @version: 1.0.0
     */
    public class DateUtil {
    
        private final static SimpleDateFormat SDF_TIME = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
        private static final SimpleDateFormat SDF_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    
        /**
         * 获取当前时间的YYYY-MM-DD HH:mm:ss格式
         */
        public static String getTime() {
            return SDF_TIME.format(new Date());
        }
    
        /**
         * 日期比较,如果s>=e 返回true 否则返回false
         */
        public static boolean compareDate(String s, String e) {
            if(fomatDate(s)==null||fomatDate(e)==null){
                return false;
            }
            return s.compareTo(e)>0;
        }
        /**
         * 日期比较,如果s>=e 返回true 否则返回false
         */
        public static boolean compareDate(Date s, Date e) {
            if(s==null||e==null){
                return false;
            }
            return  s.getTime()-e.getTime()<=5*60*1000;
        }
    
        /**
         * 格式化日期
         */
        public static Date fomatDate(String date) {
            DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
            try {
                return fmt.parse(date);
            } catch (ParseException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * 获取当前时间的后i天
         */
        public static String getAddDay(int i){
            String currentTime = DateUtil.getTime();
            GregorianCalendar gCal = new GregorianCalendar(
                    Integer.parseInt(currentTime.substring(0, 4)),
                    Integer.parseInt(currentTime.substring(5, 7)) - 1,
                    Integer.parseInt(currentTime.substring(8, 10)));
            gCal.add(GregorianCalendar.DATE, i);
            return SDF_DATE_FORMAT.format(gCal.getTime());
        }
    
        /**
         * 获取当前时间的后i天 精确到秒
         */
        public static String getAddDayTime(int i){
            Date date = new Date(System.currentTimeMillis()+ (long) i *24*60*60*1000);
            return SDF_TIME.format(date);
        }
    
        /**
         * 获取当前时间的+多少秒 精确到秒
         */
        public static String getAddDaySecond(int i){
            Date date = new Date(System.currentTimeMillis()+i* 1000L);
            return SDF_TIME.format(date);
        }
    }
  • 编写Jwt生成token工具类
    package com.gremlin.common.utils;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.CompressionCodecs;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.util.StringUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Date;
    import java.util.Map;
    
    /**
     * Description: Jwt生成token工具类
     * @author: gremlin
     * Date: 2022/6/10 15:17
     * @version: 1.0.0
     */
    @Slf4j
    public class JwtTokenUtils {
    
        @ApiModelProperty(value = "令牌签名密钥")
        private static final String tokenSignKey = "gremlin";
    
        @ApiModelProperty(value = "token有效时长30分钟")
        private static final long tokenExpiration = 30*60*1000;
    
        /**
         * 生成token
         */
        public static String generateToken(String subject, Map<String,Object> claims) {
            return Jwts.builder().setClaims(claims)
                    .setSubject(subject)
                    .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                    // 签名算法
                    .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                    // 压缩格式
                    .compressWith(CompressionCodecs.GZIP).compact();
        }
        /**
         * 判断令牌是否过期
         */
        public static Boolean isTokenExpired(String token) {
            try {
                return  getTokenBody(token).getExpiration().before(new Date());
            } catch (Exception e) {
                return false;
            }
        }
    
        /**
         * 解析token,获得subject中的信息
         */
        public static String parseToken(String token) {
            String subject = null;
            try {
                subject = getTokenBody(token).getSubject();
            } catch (Exception e) {
                log.info(String.valueOf(e));
            }
            return subject;
        }
    
        /**
         * 获取token自定义属性
         */
        public static Map<String,Object> getClaims(String token){
            Map<String,Object> claims = null;
            try {
                claims = getTokenBody(token);
            }catch (Exception e) {
                e.printStackTrace();
            }
            return claims;
        }
    
        public static Date getTokenTime(String token){
            return getTokenBody(token).getExpiration();
        }
    
        /**
         * 是否已过期
         */
        public static boolean isExpiration(String expirationTime){
            //通过redis中的失效时间进行判断
            String currentTime = DateUtil.getTime();
            if(DateUtil.compareDate(currentTime,expirationTime)){
                //当前时间比过期时间大,失效
                return true;
            }else{
                return false;
            }
        }
    
        private static Claims getTokenBody(String token){
            return  Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        }
    
        /**
         * 根据token字符串获取账号
         * @param request
         * @return
         */
        public static String getUserByJwtToken(HttpServletRequest request) {
            String jwtToken = request.getHeader("token");
            if(!StringUtils.hasText(jwtToken)) {
                return "";
            }
            Claims tokenBody = getTokenBody(jwtToken);
            return tokenBody.getSubject();
        }
    }
  • 编写redis工具配置类
    package com.gremlin.common.utils;
    
    import com.gremlin.security.vo.User;
    import io.swagger.annotations.ApiModelProperty;
    import org.apache.commons.collections4.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Component;
    
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    /**
     * Description: redis工具类
     * @author: gremlin
     * Date: 2022/6/10 14:43
     * @version: 1.0.0
     */
    @Component
    public class RedisUtils {
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        @ApiModelProperty(value = "reids 中用户信息吗存储2小时 刷新时间")
        private final int validTime = 2;
        @ApiModelProperty(value = "过期时间 秒")
        private final int expirationSeconds = 300;
    
        /**
         * 删除精确key值下所有值
         */
        public void deleteKey(String key) {
            redisTemplate.opsForHash().getOperations().delete(key);
        }
    
        /**
         * 删除key前缀值下所有值
         */
        public void deleteKeys(String key) {
            //最后一定要带上 *
            Set<String> keys = redisTemplate.keys(key + "*");
            if (CollectionUtils.isNotEmpty(keys)){
                redisTemplate.delete(keys);
            }
        }
        /**
         * 删出key 这里跟下边deleteKey()最底层实现都是一样的,应该可以通用
         */
        public void delete(String key){
            redisTemplate.opsForValue().getOperations().delete(key);
        }
    
        /**
         * 字符串获取值
         */
        public Object get(String key){
            return redisTemplate.opsForValue().get(key);
        }
    
        /**
         * 字符串存入值 默认过期时间为2小时
         */
        public void set(String key, String value){
            redisTemplate.opsForValue().set(key,value, 7200, TimeUnit.SECONDS);
        }
    
        /**
         * 字符串存入值
         */
        public void set(String key, String value,Integer expire){
            redisTemplate.opsForValue().set(key,value, expire,TimeUnit.SECONDS);
        }
    
    
        /**
         * 查询token下的刷新时间
         */
        public Object getTokenValidTimeByToken(String token) {
            return redisTemplate.opsForHash().get(token, "tokenValidTime");
        }
    
        /**
         * 查询token下的刷新时间
         *
         * @param token 查询的key
         * @return HV
         */
        public Object getUsernameByToken(String token) {
            return redisTemplate.opsForHash().get(token, "username");
        }
    
        /**
         * 查询token下的刷新时间
         *
         * @param token 查询的key
         * @return HV
         */
        public Object getIpByToken(String token) {
            return redisTemplate.opsForHash().get(token, "ip");
        }
    
        public void setTokenRefresh(String username,String token,String ip){
            //刷新时间
            Integer expire = validTime*60*60*1000;
            hset(username, "tokenValidTime",DateUtil.getAddDayTime(validTime),expire);
            hset(username, "expirationTime",DateUtil.getAddDaySecond(expirationSeconds),expire);
            hset(username, "username",username,expire);
            hset(username, "token",token,expire);
            hset(username, "ip",ip,expire);
        }
        /**
         * 添加单个
         */
        public void hset(String key,String filed,Object domain,Integer expire){
            redisTemplate.opsForHash().put(key, filed, domain);
            redisTemplate.expire(key, expire,TimeUnit.SECONDS);
        }
    
        /**
         * 判断key和field下是否有值
         */
        public Boolean hasKey(String key,String field) {
            return redisTemplate.opsForHash().hasKey(key,field);
        }
    
        /**
         * 判断key下是否有值
         */
        public Boolean hasKey(String key) {
            return redisTemplate.opsForHash().getOperations().hasKey(key);
        }
    
        /**
         * 查询key和field所确定的值
         */
        public Object hasGet(String key,String field) {
            return redisTemplate.opsForHash().get(key, field);
        }
    
        /**
         * 查询该key下所有值
         */
        public Object hasGet(String key) {
            return redisTemplate.opsForHash().entries(key);
        }
    
        /**
         * 获取用户登录信息
         */
        public static User getUser(){
            // 获取当前用户
            UserDetails userDetails
                    = (UserDetails) SecurityContextHolder.getContext()
                    .getAuthentication().getPrincipal();
            User user = new User();
            user.setUsername(userDetails.getUsername());
            return user;
        }
    
    }
  • 编写token响应类 获取token
    package com.gremlin.common.utils;
    
    import com.gremlin.security.vo.User;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Description: token响应类 获取token
     * @author: gremlin
     * Date: 2022/6/10 10:55
     * @version: 1.0.0
     */
    @Service
    public class TokenResponse {
    
        @Autowired
        private RedisUtils redisUtil;
    
        public void getResponse(HttpServletResponse response) {
            //获取用户登录信息
            User user = RedisUtils.getUser();
            // 获取Token
            Object token = redisUtil.get(user.getUsername()+"token");
            if (StringUtils.isNotBlank((String)token)) {
                response.reset();
                response.setHeader("token", String.valueOf(token));
            } else {
                response.reset();
                response.setHeader("token", String.valueOf(token));
            }
        }
    }
  • mapper类以及数据库查询类很简单就不写了

 

  追加:WebSecurityConfigurerAdapter和authenticationManager()过时配置SecurityConfig

package com.gremlin.config;

import com.gremlin.common.utils.RedisUtils;
import com.gremlin.log.service.LogService;
import com.gremlin.power.mapper.PowerManagerMapper;
import com.gremlin.power.service.PowerManagerService;
import com.gremlin.security.fifter.JwtAuthenticationTokenFilter;
import com.gremlin.security.fifter.TokenLoginFilter;
import com.gremlin.security.handler.AjaxAccessDeniedHandler;
import com.gremlin.security.handler.AjaxAuthenticationEntryPoint;
import com.gremlin.security.handler.AjaxLogoutSuccessHandler;
import com.gremlin.security.strategy.CustomizeSessionInformationExpiredStrategy;
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.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * Description:
 *
 * @author: gremlin
 * Date: 2022/7/12 17:10
 * @version: 1.0.0
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    /**
     * 注销成功返回的 JSON 格式数据给前端
     */
    @Autowired
    private AjaxLogoutSuccessHandler logoutSuccessHandler;
    /**
     * 无权访问 JSON 格式的数据
     */
    @Autowired
    private AjaxAccessDeniedHandler ajaxAccessDeniedHandler;
    @Autowired
    private AjaxAuthenticationEntryPoint authenticationEntryPoint;
    @Autowired
    private CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;
    @Autowired
    private JwtAuthenticationTokenFilter tokenAuthenticationFilter;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private LogService logService;
    @Autowired
    private PowerManagerMapper powerManagerMapper;
    @Autowired
    private PowerManagerService powerManagerService;
    /**
     * 注入AuthenticationConfiguration
     */
    @Autowired
    private AuthenticationConfiguration auth;

    /**
     * 编写AuthenticationManager的bean
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return auth.getAuthenticationManager();
    }

    /**
     * 替换旧版本中的configure(HttpSecurity http)方法
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
        http.httpBasic()
                .authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .authorizeRequests()
                //自定义放行接口
                .antMatchers(
                        "/swagger**/**",
                        "/swagger-ui.html",
                        "/swagger-resources/**",
                        "/webjars/**",
                        "/v3/**"
                ).permitAll()

                .anyRequest()
                .authenticated()
                .and().logout().logoutUrl("/logout")
                //登出处理
                .logoutSuccessHandler(logoutSuccessHandler)
                //添加关于自定义的认证过滤器和自定义的授权过滤器
                .and()
                .logout().permitAll()//注销行为任意访问
                //会话管理
                .and().sessionManagement()
                //同一账号同时登录最大用户数
                .maximumSessions(1)
                //会话信息过期策略会话信息过期策略(账号被挤下线)
                .expiredSessionStrategy(sessionInformationExpiredStrategy);

        //自定义权限拒绝处理类
        // 无权访问 JSON 格式的数据
        http.exceptionHandling().accessDeniedHandler(ajaxAccessDeniedHandler);
        // 登录验证
        http.addFilter(new TokenLoginFilter(authenticationManager(),redisUtils,logService,powerManagerMapper,powerManagerService)).httpBasic();
        // JWT Filter
        http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().antMatchers("/css/**","/js/**","/img/**","/uploads/**","**/favicon.ico");
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

 

 

 

 

 

 

 

转:https://blog.csdn.net/rq12345688/article/details/125479657

https://docs.spring.io/spring-security/reference/servlet/configuration/java.html

 

posted @ 2023-05-17 16:54  与f  阅读(858)  评论(0编辑  收藏  举报