首页 > 其他分享 >springboot3项目的搭建四.2(security登录认证配置)

springboot3项目的搭建四.2(security登录认证配置)

时间:2024-05-31 21:44:43浏览次数:30  
标签:return String private 认证 springboot3 response new security public

SpringBoot3+SpringSecurity整合

Security导包:

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

模拟Redis存储登录信息:

public class CacheEntity implements Serializable {
    private Object value;
    /**
     * 保存的时间戳
     */
    private long gmtModify;
    /**
     * 过期时间
     */
    private int expire;
 
    public Object getValue() {
        return value;
    }
 
    public void setValue(Object value) {
        this.value = value;
    }
 
    public long getGmtModify() {
        return gmtModify;
    }
 
    public void setGmtModify(long gmtModify) {
        this.gmtModify = gmtModify;
    }
 
    public int getExpire() {
        return expire;
    }
 
    public void setExpire(int expire) {
        this.expire = expire;
    }
 
    public CacheEntity(Object value, long gmtModify, int expire) {
        this.value = value;
        this.gmtModify = gmtModify;
        this.expire = expire;
    }
}

 

@Slf4j
public class LocalCache {
    /**
     * 默认的缓存容量
     */
    private static final int DEFAULT_CAPACITY = 512;
    /**
     * 最大容量
     */
    private static final int MAX_CAPACITY = 100000;
    /**
     * 刷新缓存的频率
     */
    private static final int MONITOR_DURATION = 2;
 
    // 启动监控线程
    static {
        new Thread(new TimeoutTimerThread()).start();
    }
 
    // 内部类方式实现单例
    private static class LocalCacheInstance {
        private static final LocalCache INSTANCE = new LocalCache();
    }
 
    public static LocalCache getInstance() {
        return LocalCacheInstance.INSTANCE;
    }
 
    private LocalCache() {
    }
 
    /**
     * 使用默认容量创建一个Map
     */
    private static Map<String, CacheEntity> cache = new ConcurrentHashMap<>(DEFAULT_CAPACITY);
 
    /**
     * 将key-value保存到本地缓存并制定该缓存的过期时间
     *
     * @param key
     * @param value
     * @param expireTime 过期时间,如果是-1 则表示永不过期
     * @param <T>
     * @return
     */
    public <T> boolean putValue(String key, T value, int expireTime) {
        return putCloneValue(key, value, expireTime);
    }
 
    /**
     * 将值通过序列化clone 处理后保存到缓存中,可以解决值引用的问题
     *
     * @param key
     * @param value
     * @param expireTime
     * @param <T>
     * @return
     */
    private <T> boolean putCloneValue(String key, T value, int expireTime) {
        try {
            if (cache.size() >= MAX_CAPACITY) {
                return false;
            }
            // 序列化赋值
            CacheEntity entityClone = clone(new CacheEntity(value, System.nanoTime(), expireTime));
            cache.put(key, entityClone);
            return true;
        } catch (Exception e) {
            log.error("添加缓存失败:{}", e.getMessage());
        }
        return false;
    }
 
    /**
     * 序列化 克隆处理
     *
     * @param object
     * @param <E>
     * @return
     */
    private <E extends Serializable> E clone(E object) {
        E cloneObject = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            oos.close();
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            cloneObject = (E) ois.readObject();
            ois.close();
        } catch (Exception e) {
            log.error("缓存序列化失败:{}", e.getMessage());
        }
        return cloneObject;
    }
 
    /**
     * 从本地缓存中获取key对应的值,如果该值不存则则返回null
     *
     * @param key
     * @return
     */
    public Object getValue(String key) {
        if (CollectionUtils.isEmpty(cache)) {
            return null;
        }
        CacheEntity cacheEntity = cache.get(key);
        if (ObjectUtils.isEmpty(cacheEntity)) {
            return null;
        }
        return cacheEntity.getValue();
    }
 
    public void remove(String key) {
        if (CollectionUtils.isEmpty(cache)) {
            return;
        }
        CacheEntity cacheEntity = cache.get(key);
        if (ObjectUtils.isEmpty(cacheEntity)) {
            return;
        }
        cache.remove(key);
    }
 
    /**
     * 清空所有
     */
    public void clear() {
        cache.clear();
    }
 
    /**
     * 过期处理线程
     */
    static class TimeoutTimerThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    TimeUnit.SECONDS.sleep(MONITOR_DURATION);
                    checkTime();
                } catch (Exception e) {
                    log.error("过期缓存清理失败:{}", e.getMessage());
                }
            }
        }
 
        /**
         * 过期缓存的具体处理方法  *  * @throws Exception
         */
        private void checkTime() throws Exception {
            // 开始处理过期
            for (String key : cache.keySet()) {
                CacheEntity tce = cache.get(key);
                long timoutTime = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - tce.getGmtModify());
                // 过期时间 : timoutTime
                if (tce.getExpire() > timoutTime) {
                    continue;
                }
                log.info(" 清除过期缓存 :" + key);
                //清除过期缓存和删除对应的缓存队列
                cache.remove(key);
            }
        }
    }
}

权限枚举:

//    权限值是将二进制与十进制相互转换来判断的
public enum PermissionEnum {
 
    GET_DEPARTMENT(1, "单位获取", "ROLE_GET_DEPARTMENT", 0x0000000000000001L),
    INSERT_DEPARTMENT(2, "单位增加", "ROLE_INSERT_DEPARTMENT", 0x0000000000000002L),
    UPDATE_DEPARTMENT(3, "单位修改", "ROLE_UPDATE_DEPARTMENT", 0x0000000000000004L),
    DELETE_DEPARTMENT(4, "单位删除", "ROLE_DELETE_DEPARTMENT", 0x0000000000000008L),
    ;
 
    private int id;
 
    private String permissions;
 
    private String permissionNames;
 
    private Long value;
 
    PermissionEnum(int id, String permissions, String permissionNames, Long value) {
        this.id = id;
        this.permissions = permissions;
        this.permissionNames = permissionNames;
        this.value = value;
    }
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getPermissions() {
        return permissions;
    }
 
    public void setPermissions(String permissions) {
        this.permissions = permissions;
    }
 
    public String getPermissionNames() {
        return permissionNames;
    }
 
    public void setPermissionNames(String permissionNames) {
        this.permissionNames = permissionNames;
    }
 
    public Long getValue() {
        return value;
    }
 
    public void setValue(Long value) {
        this.value = value;
    }
 
    public static List<GrantedAuthority> fromCode(Long code) {
        List<GrantedAuthority> list = new ArrayList<>();
        PermissionEnum[] codes = PermissionEnum.values();
        for (PermissionEnum state : codes) {
            if ((state.getValue() & code) > 0) {
                list.add(new SimpleGrantedAuthority(state.getPermissionNames()));
            }
        }
        return list;
    }
 
    public static List<PermissionEnum> getAuthList(Long code) {
        List<PermissionEnum> list = new ArrayList<>();
        PermissionEnum[] codes = PermissionEnum.values();
        for (PermissionEnum state : codes) {
            if ((state.getValue() & code) > 0) {
                list.add(state);
            }
        }
        return list;
    }
 
    //  获取权限值
    public static Long getPermissionCode(Integer[] auths) {
        Long code = 0x0000000000000000L;
        PermissionEnum[] codes = PermissionEnum.values();
        for (Integer auth : auths) {
            for (PermissionEnum permissionCode : codes) {
                if (auth.equals(permissionCode.getId())) {
                    code += permissionCode.getValue();
                    break;
                }
            }
        }
        return code;
    }
 
    //    获取权限数组
    public static String[] getAuths(Long code) {
        List<String> lists = new ArrayList<>();
        PermissionEnum[] codes = PermissionEnum.values();
        for (PermissionEnum state : codes) {
            if ((state.getValue() & code) > 0) {
                lists.add(state.getPermissions());
            }
        }
        return lists.toArray(new String[lists.size()]);
    }
 
    //    获取权限值
    public static Long getPermissionCode(String[] auths) {
        Long code = 0x0000000000000000L;
        PermissionEnum[] codes = PermissionEnum.values();
        for (String auth : auths) {
            for (PermissionEnum permissionCode : codes) {
                if (auth.equals(permissionCode.getPermissions())) {
                    code += permissionCode.getValue();
                    break;
                }
            }
        }
        return code;
    }
}

User实体类:

@Data
@Accessors(chain = true)
public class Users implements Serializable {
    private Long userID;
    private String userName;
    private String userPassword;
    private String userPhone;
    private String userAddress;
    private Integer userAllowErrCount;
    private Integer userErrCount;
    private Date userLastErrTime;
    private Long userRoleID;
    private Roles roles;
    private Long userDepID;
    private Department department;
    private boolean userEnable;
}

权限反序列化:

public class CustomAuthorityDeserializer extends JsonDeserializer {
    @Override
    public Object deserialize(
            JsonParser p, DeserializationContext deserializationContext
    ) throws IOException, JacksonException {
        ObjectMapper mapper = (ObjectMapper) p.getCodec();
        JsonNode jsonNode = mapper.readTree(p);
        LinkedList<GrantedAuthority> grantedAuthorities = new LinkedList<>();
        Iterator<JsonNode> elements = jsonNode.elements();
        while (elements.hasNext()) {
            JsonNode next = elements.next();
            JsonNode authority = next.get("authority");
            //将得到的值放入链表 最终返回该链表
            grantedAuthorities.add(new SimpleGrantedAuthority(authority.asText()));
        }
        return grantedAuthorities;
    }
}

用户详情类:

@JsonIgnoreProperties({"enabled", "accountNonExpired", "accountNonLocked", "credentialsNonExpired",
        "username", "password"})
public class MyUserDetail extends Users implements UserDetails, Serializable {
    List<? extends GrantedAuthority> authorities;
 
    public MyUserDetail() {
    }
 
    public MyUserDetail(Users users, List<? extends GrantedAuthority> authList) {
        this.setUserID(users.getUserID());
        this.setUserName(users.getUserName());
        this.setUserPassword(users.getUserPassword());
        this.setUserDepID(users.getUserDepID());
        this.setUserRoleID(users.getUserRoleID());
        this.authorities = authList;
    }
 
    @Override
    @JsonDeserialize(using = CustomAuthorityDeserializer.class)
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }
 
    @Override
    public String getPassword() {
        return this.getUserPassword();
    }
 
    @Override
    public String getUsername() {
        return this.getUserName();
    }
 
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
 
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
 
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
 
    @Override
    public boolean isEnabled() {
        return true;
    }
}

用户详情实现类:

@Component
public class MyUserDetailServiceImpl implements UserDetailsService {
 
    //    操作数据库,根据用户名称查询用户信息
    private final UserMapper userMapper;
 
    public MyUserDetailServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Users users = userMapper.getUserByName(username);
        Optional.ofNullable(users).orElseThrow(() -> {
            //    自定义的异常返回类和枚举
            throw new CommonException(YIXGResultEnum.USER_NOT_EXIST.getCode(),
                    YIXGResultEnum.USER_NOT_EXIST.getMessage());
        });
        if (ObjectUtils.isEmpty(users.getUserRoleID())) {
            throw new CommonException(YIXGResultEnum.USER_ROLE_NOT_EXIST.getCode(),
                    YIXGResultEnum.USER_ROLE_NOT_EXIST.getMessage());
        }
        List<GrantedAuthority> authorityList = PermissionEnum.fromCode(users.getRoles().getRolePermission());
        return new MyUserDetail(users, authorityList);
    }
}

拦截未登录请求:

/**
 * 用户发起未登录的请求会被AuthorizationFilter拦截,并抛出AccessDeniedException异常。异常被AuthenticationEntryPoint
 * 处理,默认会触发重定向到登录页。Spring Security开放了配置,允许我们自定义AuthenticationEntryPoint。
 * 那么我们就通过自定义AuthenticationEntryPoint来取消重定向行为,将接口改为返回JSON信息。
 */
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(
            HttpServletRequest request, HttpServletResponse response, AuthenticationException authException
    ) throws IOException, ServletException {
        CommonResult commonResult = new CommonResult();
        ObjectMapper objectMapper = new ObjectMapper();
        commonResult.setCode(YIXGResultEnum.LOGIN_INVALID.getCode())
                    .setMessage(YIXGResultEnum.LOGIN_INVALID.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(commonResult));
        response.getWriter().flush();
        response.getWriter().close();
    }
}

拦截没权限的请求:

public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(
            HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException
    ) throws IOException, ServletException {
        ObjectMapper objectMapper = new ObjectMapper();
        CommonResult commonResult = new CommonResult();
        commonResult.setCode(YIXGResultEnum.NO_PERMISSION.getCode())
                    .setMessage(YIXGResultEnum.NO_PERMISSION.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(commonResult));
        response.getWriter().flush();
        response.getWriter().close();
    }
}

自定义拦截器,验证token信息:

public class MyAuthenticationTokenFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(
            HttpServletRequest request, HttpServletResponse response, FilterChain filterChain
    ) throws ServletException, IOException {
        //  从header中获取验证信息
        String authHeader = request.getHeader(GlobalUtil.AUTHORIZATION);
        if (ObjectUtils.isEmpty(authHeader)) {
            filterChain.doFilter(request, response);
            return;
        }
        this.doParse(request, response, filterChain, authHeader);
    }
 
    private void doParse(
            HttpServletRequest request, HttpServletResponse response, FilterChain chain, String authHeader
    ) throws ServletException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        //  如果认证码  以规定值开头
        if (authHeader.startsWith(GlobalUtil.GRANT_TYPE)) {
            // 提取token值
            String token = authHeader.substring(GlobalUtil.GRANT_TYPE.length());
            if (ObjectUtils.isEmpty(token)) {
                chain.doFilter(request, response);
                return;
            }
            //  通过token值从缓存中取用户信息
            String userJson = (String) LocalCache.getInstance().getValue(token);
            //  转换JSON对象
 
            //JSONObject userJsonObject = JSON.parseObject(userJson);
            //  判断是否空值
            if (ObjectUtils.isEmpty(userJson)) {
//                throw new CommonException(YIXGResultEnum.INVALID_TOKEN.getCode(),
//                        YIXGResultEnum.INVALID_TOKEN.getMsg());
                chain.doFilter(request, response);
                return;
            }
            //  转换MyUserDetail对象
            MyUserDetail user = objectMapper.readValue(userJson, MyUserDetail.class);
            //MyUserDetail user = JSON.toJavaObject(userJsonObject, MyUserDetail.class);
//                MyUserDetail user = JSONObject.toJavaObject(userJsonObject, MyUserDetail.class);
            //  转换 UP 对象放到上下文中
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                    new UsernamePasswordAuthenticationToken(
                            user, user.getPassword(), user.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
        chain.doFilter(request, response);
    }
}

密码加密:

public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        return MD5Util.md5((String) rawPassword);
    }
 
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equalsIgnoreCase(MD5Util.md5((String) rawPassword));
    }
}

登录成功:

@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private final ObjectMapper objectMapper;
 
    private final LogService logService;
 
    private final UserService userService;
 
    public MyAuthenticationSuccessHandler(
            ObjectMapper objectMapper, LogService logService,
            UserService userService
    ) {
        this.objectMapper = objectMapper;
        this.logService = logService;
        this.userService = userService;
    }
 
    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            Authentication authentication
    ) throws IOException, ServletException {
        AuthenticationSuccessHandler.super.onAuthenticationSuccess(request, response, chain, authentication);
    }
 
    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication
    ) throws IOException, ServletException {
        MyUserDetail user = (MyUserDetail) authentication.getPrincipal();
        //  获取随机token 并存到Redis中
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        LocalCache.getInstance().putValue(token, objectMapper.writeValueAsString(user), 60 * 60);
        UserVO userVO = new UserVO();
        userVO.setUserName(user.getUserName())
              .setUserErrCount("0")
              .setUserLastErrTime(null);
        userService.updateUserErrCount(userVO);
 
        LogVO logVO = new LogVO();
        logVO.setLogOperateUser(user.getUserName())
             .setLogContent("登录成功")
             .setLogType("登录日志");
        logService.addLog(logVO);
 
        CommonResult commonResult = new CommonResult();
        commonResult.setCode(YIXGResultEnum.OPERATE_SUCCESS.getCode())
                    .setMessage(YIXGResultEnum.OPERATE_SUCCESS.getMessage())
                    .setToken(token)
                    .setCurrentUser(user.getUserName())
                    .setCurrentUserId(user.getUserID());
 
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(commonResult));
        response.getWriter().flush();
        response.getWriter().close();
    }
}

登录失败:

@Component
@Slf4j
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    private final ObjectMapper objectMapper;
 
    private final UserService userService;
 
    public MyAuthenticationFailureHandler(ObjectMapper objectMapper, UserService userService) {
        this.objectMapper = objectMapper;
        this.userService = userService;
    }
 
    @Override
    public void onAuthenticationFailure(
            HttpServletRequest request, HttpServletResponse response, AuthenticationException exception
    ) throws IOException, ServletException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        CommonResult result = userService.getUserByUserName(
                new UserVO().setUserName(request.getParameter("username")));
        Users users = (Users) result.getObjectData();
 
        if (Objects.equals(result.getCode(), YIXGResultEnum.OPERATE_SUCCESS.getCode())) {
            UserVO userVO = new UserVO();
            userVO.setUserName(users.getUserName())
                  .setUserErrCount(String.valueOf((users.getUserErrCount() + 1)))
                  .setUserLastErrTime(sdf.format(new Date()));
            userService.updateUserErrCount(userVO);
        }
        
        CommonResult commonResult = new CommonResult();
        commonResult.setCode(YIXGResultEnum.PASSWORD_OR_USERNAME_ERROR.getCode())
                    .setMessage(YIXGResultEnum.PASSWORD_OR_USERNAME_ERROR.getMessage());
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(commonResult));
        response.getWriter().flush();
        response.getWriter().close();
    }
}

登出成功:

@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    private final ObjectMapper objectMapper;
 
    private final LogService logService;
 
    public MyLogoutSuccessHandler(ObjectMapper objectMapper, LogService logService) {
        this.objectMapper = objectMapper;
        this.logService = logService;
    }
 
    @Override
    public void onLogoutSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication
    ) throws IOException, ServletException {
        String authHeader = request.getHeader(GlobalUtil.AUTHORIZATION);
        String authToken = authHeader.substring(GlobalUtil.GRANT_TYPE.length());
 
        String userJson = (String) LocalCache.getInstance().getValue(authToken);
        if (ObjectUtils.isEmpty(userJson)) {
            CommonResult commonResult = new CommonResult();
            commonResult.setCode(YIXGResultEnum.OPERATE_FAILURE.getCode())
                        .setMessage(YIXGResultEnum.OPERATE_FAILURE.getMessage());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(commonResult));
            response.getWriter().flush();
            response.getWriter().close();
            return;
        }
        
        MyUserDetail user = objectMapper.readValue(userJson, MyUserDetail.class);
 
        LocalCache.getInstance().putValue(authToken, "", 1);
 
        LogVO logVO = new LogVO();
        logVO.setLogOperateUser(user.getUserName())
             .setLogContent("登出成功")
             .setLogType("登录日志");
        logService.addLog(logVO);
 
        CommonResult commonResult = new CommonResult();
        commonResult.setCode(YIXGResultEnum.OPERATE_SUCCESS.getCode())
                    .setMessage(YIXGResultEnum.OPERATE_SUCCESS.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(commonResult));
        response.getWriter().flush();
        response.getWriter().close();
    }
}

Security核心配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
 
    private final MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
 
    private final MyAuthenticationFailureHandler myAuthenticationFailureHandler;
 
    private final MyLogoutSuccessHandler myLogoutSuccessHandler;
 
    private final UserDetailsService userDetailsService;
 
    public SecurityConfig(
            MyAuthenticationSuccessHandler myAuthenticationSuccessHandler,
            MyAuthenticationFailureHandler myAuthenticationFailureHandler,
            MyLogoutSuccessHandler myLogoutSuccessHandler, UserDetailsService userDetailsService
    ) {
        this.myAuthenticationSuccessHandler = myAuthenticationSuccessHandler;
        this.myAuthenticationFailureHandler = myAuthenticationFailureHandler;
        this.myLogoutSuccessHandler = myLogoutSuccessHandler;
        this.userDetailsService = userDetailsService;
    }
 
    @Bean
    public AuthenticationManager authenticationManager(
            AuthenticationConfiguration authenticationConfiguration
    ) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }
 
    @Bean
    public MyAuthenticationTokenFilter myAuthenticationTokenFilter() {
        return new MyAuthenticationTokenFilter();
    }
 
    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                //  禁用basic明文验证
                .httpBasic(Customizer.withDefaults())
                //  基于 token ,不需要 csrf
                .csrf(AbstractHttpConfigurer::disable)
                //  禁用默认登录页
                .formLogin(fl -> fl.loginProcessingUrl("/login")
                                   .usernameParameter("username")
                                   .passwordParameter("password")
                                   .successHandler(myAuthenticationSuccessHandler)
                                   .failureHandler(myAuthenticationFailureHandler)
                                   .permitAll())
                //  禁用默认登出页
                .logout(lt -> lt.logoutSuccessHandler(myLogoutSuccessHandler))
                //  基于 token , 不需要 session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                //  设置 处理鉴权失败、认证失败
                .exceptionHandling(
                        exceptions -> exceptions.authenticationEntryPoint(new MyAuthenticationEntryPoint())
                                                .accessDeniedHandler(new MyAccessDeniedHandler())
                )
                //  下面开始设置权限
                .authorizeHttpRequests(authorizeHttpRequest -> authorizeHttpRequest
                        //  允许所有 OPTIONS 请求
                        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                        //  允许直接访问 授权登录接口
                        .requestMatchers(HttpMethod.POST, "/web/authenticate").permitAll()
                        //  允许 SpringMVC 的默认错误地址匿名访问
                        .requestMatchers("/error").permitAll()
                        //  其他所有接口必须有Authority信息,Authority在登录成功后的UserDetailImpl对象中默认设置“ROLE_USER”
                        //.requestMatchers("/**").hasAnyAuthority("ROLE_USER")
                        .requestMatchers("/heartBeat/**", "/main/**").permitAll()
                        //  允许任意请求被已登录用户访问,不检查Authority
                        .anyRequest().authenticated()
                )
                //  添加过滤器
                .addFilterBefore(myAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                .build();
    }
 
    @Bean
    public UserDetailsService userDetailsService() {
        return userDetailsService::loadUserByUsername;
    }
 
    /**
     * 调用loadUserByUserName获取userDetail信息,在AbstractUserDetailsAuthenticationProvider里执行用户状态检查
     *
     * @return
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }
 
//    @Bean
//    public WebSecurityCustomizer webSecurityCustomizer() {
//        return (web) -> web.ignoring().requestMatchers();
//    }
 
    /**
     * 配置跨源访问(CORS)
     *
     * @return
     */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
 
}

 

 

 

 

 

 

 

转: https://blog.csdn.net/qq_40107343/article/details/136086463

 

标签:return,String,private,认证,springboot3,response,new,security,public
From: https://www.cnblogs.com/fps2tao/p/18225317

相关文章

  • springboot3项目的搭建四(security登录认证配置)
    springboot3项目的搭建四(security登录认证配置)  <!--security安全配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifact......
  • SpringSecurity权限验证
    目录我们先用默认的一个访问拦截页面第二种,我们可以自己写一个登录的页面,也就是没有权限被拦截之后的登录页面我们先用默认的一个访问拦截页面首先先加入我们的Security的一个依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>s......
  • WEB安全:Content Security Policy (CSP) 详解
    ContentSecurityPolicy(CSP)是一种强大的网页安全机制,用于防止跨站脚本(XSS)和其他注入攻击。通过设置一系列的内容安全策略,CSP可以限制网页可以加载的资源,从而保护用户数据和网站的安全性。什么是XSS攻击?跨站脚本攻击(XSS)是一种常见的安全漏洞,攻击者通过注......
  • nginx配置下载站,增加用户认证,增加统计功能
    1.配置文件如下server{listen80;server_namevideo.tom.com;error_log/var/log/nginx/video.tom.cn/err.lognotice;access_log/var/log/nginx/video.tom.cn/access.logmain;root/app/code/video;charsetutf8;#支持中文autoindex......
  • 【网络通信】初探Google的reCAPTCHA安全认证技术
        在数字化日益普及的今天,如何有效保护网站免受恶意攻击和滥用成为了每个网站管理员和开发者必须面对的重要问题。而reCAPTCHA正是Google提供的一种强大且智能的解决方案,旨在通过人机验证来增强网站的安全性。一、reCAPTCHA简介        reCAPTCHA是Google推......
  • springboot3项目的搭建三(统一返回异常等)
    springboot3项目的搭建三(统一返回异常等) 一、统一返回(其实两部分,一个是返回错误码可枚举可类,另一个是返回的实体其中data是泛型)1.返回码:packagecom.qiqi.common.constants;publicenumReturnCode{SUCCESS(200,"操作成功"),NEED_LOGIN(401,"需要登录后操作......
  • 6.基于传统的Cookie和Session实现用户的认证授权
    6.1概述RBAC(Role-BasedAccessControl,基于角色的访问控制)权限按钮控制是一种细粒度的权限管理方式,它允许系统管理员根据用户的角色来精确控制用户界面中功能按钮的可见性和可用性。在RBAC模型中,权限不仅限于访问某个页面或模块,还可以细化到页面上每个操作按钮的权限。......
  • AJ-Report 认证绕过与远程代码执行漏洞(CNVD-2024-15077)
    AJ-Report是全开源的一个BI平台。在其1.4.0版本及以前,存在一处认证绕过漏洞,攻击者利用该漏洞可以绕过权限校验并执行任意代码。补丁对比方法一从docker拖出代码,去gitee下载发行版,便于对比编译后的class。方法二查看git的commit记录,可以直接看到修改了哪些内容!后面要去学习......
  • 【Spring Security】Error:A granted authority textual representation is required
     Security出错了! 分析:Debug跑后 排查是Security中的UserDetails.getAuthorities()在创建SimpleGrantedAuthorityauthority时,所传递的授权信息是空的,导致SimpleGrantedAuthorityauthority出现异常;报出Agrantedauthoritytextualrepresentationisreq......
  • C++语言实现身份证实名认证、身份证上的文字识别接口
    实名认证是什么意思呢?一般指的是对用户资料真实性进行的验证审核,这样有利于建立完善且可靠的互联网环境。如果交易双方使用的都是虚假信息,那么在诸多环节会存在很大的风险。另外,还有游戏平台对玩家进行实名认证,防止未成年人注册。翔云身份证实名认证接口,通过核验身份证二......