目录

Spring-Security

Spring-Webflux

注意

编码

项目环境版本

gradle 依赖

Spring-Security配置

1. Security核心配置

2.用户认证

3.1 自定义登录成功Handler

3.2 自定义登录失败Handler

3.3 自定义未认证Handler

3.4 自定义鉴权失败Handler

4.自定义JWT Token认证管理

5.自定义鉴权管理

2.springsecruity密码判断

3.流程

3.尚硅谷springsecurity

3.3两个重要接口

3.3.1认证

3.3.2自定义登入

403设计​编辑

3.5用户注销

3.6免登陆

4过滤器方式

4.1maven---直接引用--配置

4.2 entity

4.3 filter

4.3.1 访问过滤器  获取request--token

4.3.2 登录过滤器   成功 获取token 保存redis

4.4密码的处理方法类型

4.4退出

4.5token生成

4.6未授权

4.7 XML

4.7 jwt

4.8 MD5

4.9 R


Spring Cloud Gateway是基于Spring Boot 2.x,Spring WebFlux和Project Reactor构建的。结果,当您使用Spring Cloud Gateway时,许多您熟悉的同步库(例如,Spring Data和Spring Security)和模式可能不适用。如果您不熟悉这些项目,建议您在使用Spring Cloud Gateway之前先阅读它们的文档以熟悉一些新概念。

Spring-Security

Spring Security是一个提供身份验证,授权和保护以防止常见攻击的框架。凭借对命令式和响应式应用程序的一流支持,它是用于保护基于Spring的应用程序的事实上的标准。

Spring-Webflux

Spring框架中包含的原始Web框架Spring Web MVC是专门为Servlet API和Servlet容器而构建的。响应式堆栈Web框架Spring WebFlux在稍后的5.0版中添加。它是完全无阻塞的,支持 Reactive Streams背压,并在Netty,Undertow和Servlet 3.1+容器等服务器上运行。

这两个Web框架都反映了其源模块的名称(spring-webmvc和 spring-webflux),并在Spring Framework中并存。每个模块都是可选的。应用程序可以使用一个模块,也可以使用两个模块,在某些情况下,也可以使用两个模块,例如,带有react的Spring MVC控制器WebClient

注意

由于Web容器不同,在Gateway项目中使用的WebFlux,是不能和Spring-Web混合使用的。 Spring MVC和 WebFlux 的区别:


编码

项目环境版本

  1. Spring-Cloud:2020.0.1
  2. Spring-Boot: 2.4.3

gradle 依赖

dependencies {implementation('org.springframework.cloud:spring-cloud-starter-gateway','org.springframework.boot:spring-boot-starter-security')
}
复制代码

Spring-Security配置

spring security设置要采用响应式配置,基于WebFlux中WebFilter实现,与Spring MVC的Security是通过Servlet的Filter实现类似,也是一系列filter组成的过滤链。

Reactor与传统MVC配置对应:

webflux mvc 作用
@EnableWebFluxSecurity @EnableWebSecurity 开启security配置
ServerAuthenticationSuccessHandler AuthenticationSuccessHandler 登录成功Handler
ServerAuthenticationFailureHandler AuthenticationFailureHandler 登陆失败Handler
ReactiveAuthorizationManager AuthorizationManager 认证管理
ServerSecurityContextRepository SecurityContextHolder 认证信息存储管理
ReactiveUserDetailsService UserDetailsService 用户登录
ReactiveAuthorizationManager AccessDecisionManager 鉴权管理
ServerAuthenticationEntryPoint AuthenticationEntryPoint 未认证Handler
ServerAccessDeniedHandler AccessDeniedHandler 鉴权失败Handler

1. Security核心配置

package com.pluto.gateway.security;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.DelegatingReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.util.LinkedList;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 10:56* @description webflux security核心配置类*/
@EnableWebFluxSecurity
public class WebfluxSecurityConfig {@Resourceprivate DefaultAuthorizationManager defaultAuthorizationManager;@Resourceprivate UserDetailsServiceImpl userDetailsServiceImpl;@Resourceprivate DefaultAuthenticationSuccessHandler defaultAuthenticationSuccessHandler;@Resourceprivate DefaultAuthenticationFailureHandler defaultAuthenticationFailureHandler;@Resourceprivate TokenAuthenticationManager tokenAuthenticationManager;@Resourceprivate DefaultSecurityContextRepository defaultSecurityContextRepository;@Resourceprivate DefaultAuthenticationEntryPoint defaultAuthenticationEntryPoint;@Resourceprivate DefaultAccessDeniedHandler defaultAccessDeniedHandler;/*** 自定义过滤权限*/@Value("${security.noFilter}")private String noFilter;@Beanpublic SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {httpSecurity// 登录认证处理.authenticationManager(reactiveAuthenticationManager()).securityContextRepository(defaultSecurityContextRepository)// 请求拦截处理.authorizeExchange(exchange -> exchange.pathMatchers(noFilter).permitAll().pathMatchers(HttpMethod.OPTIONS).permitAll().anyExchange().access(defaultAuthorizationManager)).formLogin()// 自定义处理.authenticationSuccessHandler(defaultAuthenticationSuccessHandler).authenticationFailureHandler(defaultAuthenticationFailureHandler).and().exceptionHandling().authenticationEntryPoint(defaultAuthenticationEntryPoint).and().exceptionHandling().accessDeniedHandler(defaultAccessDeniedHandler).and().csrf().disable();return httpSecurity.build();}/*** BCrypt密码编码*/@Bean("passwordEncoder")public PasswordEncoder passwordEncoder() {return PasswordEncoderFactories.createDelegatingPasswordEncoder();}/*** 注册用户信息验证管理器,可按需求添加多个按顺序执行*/@BeanReactiveAuthenticationManager reactiveAuthenticationManager() {LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();managers.add(authentication -> {// 其他登陆方式 (比如手机号验证码登陆) 可在此设置不得抛出异常或者 Mono.error return Mono.empty();});// 必须放最后不然会优先使用用户名密码校验但是用户名密码不对时此 AuthenticationManager 会调用 Mono.error 造成后面的 AuthenticationManager 不生效managers.add(new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsServiceImpl));managers.add(tokenAuthenticationManager);return new DelegatingReactiveAuthenticationManager(managers);}
}
复制代码

2.用户认证

package com.pluto.gateway.security;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.io.Serializable;
import java.util.Collection;/*** @author ShiLei* @version 1.0.0* @date 2021/3/10 13:15* @description 自定义用户信息*/
public class SecurityUserDetails extends User implements Serializable {private Long userId;public SecurityUserDetails(String username, String password, Collection<? extends GrantedAuthority> authorities, Long userId) {super(username, password, authorities);this.userId = userId;}public SecurityUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities, Long userId) {super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);this.userId = userId;}public Long getUserId() {return userId;}public void setUserId(Long userId) {this.userId = userId;}
}复制代码
package com.pluto.gateway.security;import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.util.ArrayList;/*** @author ceshi* @date 2021/3/9 14:03* @description 用户登录处理* @version 1.0.0*/@Service
public class UserDetailsServiceImpl implements ReactiveUserDetailsService {@Resourceprivate PasswordEncoder passwordEncoder;@Overridepublic Mono<UserDetails> findByUsername(String username) {SecurityUserDetails securityUserDetails = new SecurityUserDetails("user",passwordEncoder.encode("user"),true, true, true, true, new ArrayList<>(),1L);return Mono.just(securityUserDetails);}
}
复制代码

3.1 自定义登录成功Handler

package com.pluto.gateway.security;import com.alibaba.fastjson.JSONObject;
import com.pluto.common.basic.utils.JwtTokenUtil;
import com.pluto.common.basic.utils.ResultVoUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 15:00* @description 登录成功处理*/
@Component
public class DefaultAuthenticationSuccessHandler implements ServerAuthenticationSuccessHandler {/*** token 过期时间*/@Value("${jwt.token.expired}")private int jwtTokenExpired;/*** 刷新token 时间*/@Value("${jwt.token.refresh.expired}")private int jwtTokenRefreshExpired;@Overridepublic Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {return Mono.defer(() -> Mono.just(webFilterExchange.getExchange().getResponse()).flatMap(response -> {DataBufferFactory dataBufferFactory = response.bufferFactory();// 生成JWT tokenMap<String, Object> map = new HashMap<>(2);SecurityUserDetails userDetails = (SecurityUserDetails) authentication.getPrincipal();map.put("userId", userDetails.getUserId());map.put("username", userDetails.getUsername());map.put("roles",userDetails.getAuthorities());String token = JwtTokenUtil.generateToken(map, userDetails.getUsername(), jwtTokenExpired);String refreshToken = JwtTokenUtil.generateToken(map, userDetails.getUsername(), jwtTokenRefreshExpired);Map<String, Object> tokenMap = new HashMap<>(2);tokenMap.put("token", token);tokenMap.put("refreshToken", refreshToken);DataBuffer dataBuffer = dataBufferFactory.wrap(JSONObject.toJSONString(ResultVoUtil.success(tokenMap)).getBytes());return response.writeWith(Mono.just(dataBuffer));}));}
}
复制代码

3.2 自定义登录失败Handler

package com.pluto.gateway.security;import com.alibaba.fastjson.JSONObject;
import com.pluto.common.basic.enums.UserStatusCodeEnum;
import com.pluto.common.basic.utils.ResultVoUtil;
import com.pluto.common.basic.vo.ResultVO;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Map;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 15:14* @description 登录失败处理*/
@Component
public class DefaultAuthenticationFailureHandler implements ServerAuthenticationFailureHandler {@Overridepublic Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) {return Mono.defer(() -> Mono.just(webFilterExchange.getExchange().getResponse()).flatMap(response -> {DataBufferFactory dataBufferFactory = response.bufferFactory();ResultVO<Map<String, Object>> resultVO = ResultVoUtil.error();// 账号不存在if (exception instanceof UsernameNotFoundException) {resultVO = ResultVoUtil.failed(UserStatusCodeEnum.ACCOUNT_NOT_EXIST);// 用户名或密码错误} else if (exception instanceof BadCredentialsException) {resultVO = ResultVoUtil.failed(UserStatusCodeEnum.LOGIN_PASSWORD_ERROR);// 账号已过期} else if (exception instanceof AccountExpiredException) {resultVO = ResultVoUtil.failed(UserStatusCodeEnum.ACCOUNT_EXPIRED);// 账号已被锁定} else if (exception instanceof LockedException) {resultVO = ResultVoUtil.failed(UserStatusCodeEnum.ACCOUNT_LOCKED);// 用户凭证已失效} else if (exception instanceof CredentialsExpiredException) {resultVO = ResultVoUtil.failed(UserStatusCodeEnum.ACCOUNT_CREDENTIAL_EXPIRED);// 账号已被禁用} else if (exception instanceof DisabledException) {resultVO = ResultVoUtil.failed(UserStatusCodeEnum.ACCOUNT_DISABLE);}DataBuffer dataBuffer = dataBufferFactory.wrap(JSONObject.toJSONString(resultVO).getBytes());return response.writeWith(Mono.just(dataBuffer));}));}
}
复制代码

3.3 自定义未认证Handler

package com.pluto.gateway.security;import com.alibaba.fastjson.JSONObject;
import com.pluto.common.basic.enums.UserStatusCodeEnum;
import com.pluto.common.basic.utils.ResultVoUtil;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 15:17* @description 未认证处理*/
@Component
public class DefaultAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {@Overridepublic Mono<Void> commence(ServerWebExchange exchange, AuthenticationException ex) {return Mono.defer(() -> Mono.just(exchange.getResponse())).flatMap(response -> {  response.setStatusCode(HttpStatus.UNAUTHORIZED);response.getHeaders().setContentType(MediaType.APPLICATION_JSON);DataBufferFactory dataBufferFactory = response.bufferFactory();String result = JSONObject.toJSONString(ResultVoUtil.failed(UserStatusCodeEnum.USER_UNAUTHORIZED));DataBuffer buffer = dataBufferFactory.wrap(result.getBytes(Charset.defaultCharset()));return response.writeWith(Mono.just(buffer));});}
}
复制代码

3.4 自定义鉴权失败Handler

package com.pluto.gateway.security;import com.alibaba.fastjson.JSONObject;
import com.pluto.common.basic.enums.UserStatusCodeEnum;
import com.pluto.common.basic.utils.ResultVoUtil;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 11:12* @description 鉴权管理*/
@Component
public class DefaultAccessDeniedHandler implements ServerAccessDeniedHandler {@Overridepublic Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException denied) {return Mono.defer(() -> Mono.just(exchange.getResponse())).flatMap(response -> {response.setStatusCode(HttpStatus.OK);response.getHeaders().setContentType(MediaType.APPLICATION_JSON);DataBufferFactory dataBufferFactory = response.bufferFactory();String result = JSONObject.toJSONString(ResultVoUtil.failed(UserStatusCodeEnum.PERMISSION_DENIED));DataBuffer buffer = dataBufferFactory.wrap(result.getBytes(Charset.defaultCharset()));return response.writeWith(Mono.just(buffer));});}
}
复制代码

4.自定义JWT Token认证管理

package com.pluto.gateway.security;import org.apache.commons.lang3.StringUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.util.List;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 16:27* @description 存储认证授权的相关信息*/
@Component
public class DefaultSecurityContextRepository implements ServerSecurityContextRepository {public final static String TOKEN_HEADER = "Authorization";public final static String BEARER = "Bearer ";@Resourceprivate TokenAuthenticationManager tokenAuthenticationManager;@Overridepublic Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {return Mono.empty();}@Overridepublic Mono<SecurityContext> load(ServerWebExchange exchange) {ServerHttpRequest request = exchange.getRequest();List<String> headers = request.getHeaders().get(TOKEN_HEADER);if (!CollectionUtils.isEmpty(headers)) {String authorization = headers.get(0);if (StringUtils.isNotEmpty(authorization)) {String token = authorization.substring(BEARER.length());if (StringUtils.isNotEmpty(token)) {return tokenAuthenticationManager.authenticate(new UsernamePasswordAuthenticationToken(token, null)).map(SecurityContextImpl::new);}}}return Mono.empty();}
}
复制代码
package com.pluto.gateway.security;import com.pluto.common.basic.utils.JwtTokenUtil;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Collection;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 13:23* @description token 认证处理*/
@Component
@Primary
public class TokenAuthenticationManager implements ReactiveAuthenticationManager {@Override@SuppressWarnings("unchecked")public Mono<Authentication> authenticate(Authentication authentication) {return Mono.just(authentication).map(auth -> JwtTokenUtil.parseJwtRsa256(auth.getPrincipal().toString())).map(claims -> {Collection<? extends GrantedAuthority> roles = (Collection<? extends GrantedAuthority>)                     claims.get("roles");return new UsernamePasswordAuthenticationToken(claims.getSubject(),null,roles);});}
}
复制代码

5.自定义鉴权管理

package com.pluto.gateway.security;import com.alibaba.fastjson.JSONObject;
import com.pluto.common.basic.enums.UserStatusCodeEnum;
import com.pluto.common.basic.utils.ResultVoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Collection;/*** @author ShiLei* @version 1.0.0* @date 2021/3/11 13:10* @description 用户权限鉴权处理*/
@Component
@Slf4j
public class DefaultAuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {private final AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext authorizationContext) {return authentication.map(auth -> {ServerWebExchange exchange = authorizationContext.getExchange();ServerHttpRequest request = exchange.getRequest();Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();for (GrantedAuthority authority : authorities) {String authorityAuthority = authority.getAuthority();String path = request.getURI().getPath();// TODO// 查询用户访问所需角色进行对比if (antPathMatcher.match(authorityAuthority, path)) {log.info(String.format("用户请求API校验通过,GrantedAuthority:{%s}  Path:{%s} ", authorityAuthority, path));return new AuthorizationDecision(true);}}return new AuthorizationDecision(false);}).defaultIfEmpty(new AuthorizationDecision(false));}@Overridepublic Mono<Void> verify(Mono<Authentication> authentication, AuthorizationContext object) {return check(authentication, object).filter(AuthorizationDecision::isGranted).switchIfEmpty(Mono.defer(() -> {String body = JSONObject.toJSONString(ResultVoUtil.failed(UserStatusCodeEnum.PERMISSION_DENIED));return Mono.error(new AccessDeniedException(body));})).flatMap(d -> Mono.empty());}
}
复制代码

2.springsecruity密码判断

下面看看是哪里进行的密码比较

1 /spring-security-core-5.1.4.RELEASE-sources.jar!/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java

public Authentication authenticate(Authentication authentication)  throws AuthenticationException {......try {preAuthenticationChecks.check(user);// 重点看  additionalAuthenticationChecks  密码判断additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);         }catch (AuthenticationException exception) {if (cacheWasUsed) {// There was a problem, so try again after checking// we're using latest data (i.e. not from the cache)cacheWasUsed = false;user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);preAuthenticationChecks.check(user);additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);}else {throw exception;}}postAuthenticationChecks.check(user);......return createSuccessAuthentication(principalToReturn, authentication, user);
}
2 /spring-security-core-5.1.4.RELEASE-sources.jar!/org/springframework/security/authentication/dao/DaoAuthenticationProvider.javaprotected void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {if (authentication.getCredentials() == null) {logger.debug("Authentication failed: no credentials provided");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials"));}String presentedPassword = authentication.getCredentials().toString();// 密码比较就在这个地方,前面这个是用户输入的密码,后面这个是数据库存的密码,一致则通过if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {logger.debug("Authentication failed: password does not match stored value");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials"));}
}

3.流程

用户信息 还可以存放权限信息

3.尚硅谷springsecurity

3.3两个重要接口

3.3.1认证

3.3.2自定义登入

3.3.3

403设计

3.5注解访问

3.5用户注销

3.6免登陆

 

密码

4过滤器方式

4.1maven---直接引用--配置

package com.atguigu.serurity.config;import com.atguigu.serurity.filter.TokenAuthenticationFilter;
import com.atguigu.serurity.filter.TokenLoginFilter;
import com.atguigu.serurity.security.DefaultPasswordEncoder;
import com.atguigu.serurity.security.TokenLogoutHandler;
import com.atguigu.serurity.security.TokenManager;
import com.atguigu.serurity.security.UnauthorizedEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;/*** <p>* Security配置类* </p>** @author qy* @since 2019-11-18*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {private UserDetailsService userDetailsService;//用户详情服务private TokenManager tokenManager;//令牌管理器private DefaultPasswordEncoder defaultPasswordEncoder;//默认密码编码器private RedisTemplate redisTemplate;//Redis 模板//令牌网络安全配置@Autowiredpublic TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,TokenManager tokenManager, RedisTemplate redisTemplate) {this.userDetailsService = userDetailsService;this.defaultPasswordEncoder = defaultPasswordEncoder;this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}/*** 配置设置* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {System.out.println("configure(HttpSecurity http)"+http);http.exceptionHandling().authenticationEntryPoint(new UnauthorizedEntryPoint()).and().csrf().disable().authorizeRequests().anyRequest().authenticated().and().logout().logoutUrl("/admin/acl/index/logout").addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and().addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate)).addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();}/*** 密码处理* @param auth* @throws Exception* 身份验证管理器生成器*/@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);}/*** 配置哪些请求不拦截* @param web* @throws Exception*/@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/api/**","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");}
}

4.2 entity

package com.atguigu.serurity.entity;import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/*** <p>* 安全认证用户详情信息* </p>** @author qy* @since 2019-11-08*/
@Data
@Slf4j
public class SecurityUser implements UserDetails {//当前登录用户private transient User currentUserInfo;//当前权限private List<String> permissionValueList;public SecurityUser() {}public SecurityUser(User user) {if (user != null) {this.currentUserInfo = user;}}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {Collection<GrantedAuthority> authorities = new ArrayList<>();for(String permissionValue : permissionValueList) {if(StringUtils.isEmpty(permissionValue)) continue;SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);authorities.add(authority);}return authorities;}@Overridepublic String getPassword() {return currentUserInfo.getPassword();}@Overridepublic String getUsername() {return currentUserInfo.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}
package com.atguigu.serurity.entity;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;import java.io.Serializable;/*** <p>* 用户实体类* </p>** @author qy* @since 2019-11-08*/
@Data
@ApiModel(description = "用户实体类")
public class User implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "微信openid")private String username;@ApiModelProperty(value = "密码")private String password;@ApiModelProperty(value = "昵称")private String nickName;@ApiModelProperty(value = "用户头像")private String salt;@ApiModelProperty(value = "用户签名")private String token;}

4.3 filter

4.3.1 访问过滤器  获取request--token

package com.atguigu.serurity.filter;import com.atguigu.commonutils.R;
import com.atguigu.commonutils.ResponseUtil;
import com.atguigu.serurity.security.TokenManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;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.ArrayList;
import java.util.Collection;
import java.util.List;/*** <p>*               访问过滤器* </p>** @author qy* @since 2019-11-08*/
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenAuthenticationFilter(AuthenticationManager authManager, TokenManager tokenManager,RedisTemplate redisTemplate) {super(authManager);this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}@Overrideprotected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)throws IOException, ServletException {logger.info("=======TokenAuthenticationFilter-doFilterInternal=========="+req.getRequestURI());System.out.println("req.getRequestURI().indexOf(\"admin\")"+req.getRequestURI().indexOf("admin"));System.out.println("doFilterInternal-req"+req);System.out.println("doFilterInternal-req.getRequestURI()"+req.getRequestURI());
//        if(req.getRequestURI().indexOf("admin") == 1) {
//            chain.doFilter(req, res);
//            return;
//        }UsernamePasswordAuthenticationToken authentication = null;try {authentication = getAuthentication(req);System.out.println("doFilterInternal-authentication"+authentication);} catch (Exception e) {ResponseUtil.out(res, R.error());}if (authentication != null) {SecurityContextHolder.getContext().setAuthentication(authentication);} else {ResponseUtil.out(res, R.error());}/*将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是你请求的资源。 一般filter都是一个链,web.xml 里面配置了几个就有几个。一个一个的连在一起 request -> filter1 -> filter2 ->filter3 -> .... -> request resource.
*/chain.doFilter(req, res);}private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {// token置于header里String token = request.getHeader("token");if (token != null && !"".equals(token.trim())) {String userName = tokenManager.getUserFromToken(token);List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(userName);Collection<GrantedAuthority> authorities = new ArrayList<>();for(String permissionValue : permissionValueList) {if(StringUtils.isEmpty(permissionValue)) continue;SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);authorities.add(authority);}if (!StringUtils.isEmpty(userName)) {return new UsernamePasswordAuthenticationToken(userName, token, authorities);}return null;}return null;}
}

4.3.2 登录过滤器   成功 获取token 保存redis

package com.atguigu.serurity.filter;import com.atguigu.commonutils.R;
import com.atguigu.commonutils.ResponseUtil;
import com.atguigu.serurity.entity.SecurityUser;
import com.atguigu.serurity.entity.User;
import com.atguigu.serurity.security.TokenManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;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.ArrayList;/*** <p>* 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验* </p>** @author qy* @since 2019-11-08*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {private AuthenticationManager authenticationManager;private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {this.authenticationManager = authenticationManager;this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;this.setPostOnly(false);this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST"));}@Overridepublic Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)throws AuthenticationException {try {User user = new ObjectMapper().readValue(req.getInputStream(), User.class);return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));} catch (IOException e) {throw new RuntimeException(e);}}/*** 登录成功* @param req* @param res* @param chain* @param auth* @throws IOException* @throws ServletException*/@Overrideprotected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,Authentication auth) throws IOException, ServletException {SecurityUser user = (SecurityUser) auth.getPrincipal();String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());ResponseUtil.out(res, R.ok().data("token", token));}/*** 登录失败* @param request* @param response* @param e* @throws IOException* @throws ServletException*/@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,AuthenticationException e) throws IOException, ServletException {ResponseUtil.out(response, R.error());}
}

4.4密码的处理方法类型

package com.atguigu.serurity.security;import com.atguigu.commonutils.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;/*** <p>* t密码的处理方法类型* </p>** @author qy* @since 2019-11-08*/
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {public DefaultPasswordEncoder() {this(-1);}/*** @param strength*            the log rounds to use, between 4 and 31*/public DefaultPasswordEncoder(int strength) {}/** 密码加密* */public String encode(CharSequence rawPassword) {return MD5.encrypt(rawPassword.toString());}/** 密码是否相等* */public boolean matches(CharSequence rawPassword, String encodedPassword) {return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));}
}

4.4退出

package com.atguigu.serurity.security;import com.atguigu.commonutils.R;
import com.atguigu.commonutils.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** <p>* 登出业务逻辑类* </p>** @author qy* @since 2019-11-08*/
public class TokenLogoutHandler implements LogoutHandler {private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}@Overridepublic void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {String token = request.getHeader("token");if (token != null) {tokenManager.removeToken(token);//清空当前用户缓存中的权限数据String userName = tokenManager.getUserFromToken(token);redisTemplate.delete(userName);}ResponseUtil.out(response, R.ok());}}

4.5token生成

package com.atguigu.serurity.security;import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;import java.util.Date;/*** <p>* token管理* </p>** @author qy* @since 2019-11-08*/
@Component
public class TokenManager {private long tokenExpiration = 24*60*60*1000;private String tokenSignKey = "123456";public String createToken(String username) {String token = Jwts.builder().setSubject(username).setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)).signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();return token;}public String getUserFromToken(String token) {String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();return user;}public void removeToken(String token) {//jwttoken无需删除,客户端扔掉即可。}}

4.6未授权

package com.atguigu.serurity.security;import com.atguigu.commonutils.R;
import com.atguigu.commonutils.ResponseUtil;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** <p>* 未授权的统一处理方式* </p>** @author qy* @since 2019-11-08*/
public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response,AuthenticationException authException) throws IOException, ServletException {ResponseUtil.out(response, R.error());}
}

4.7 XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>commont</artifactId><groupId>com.atguigu</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>spring_security</artifactId><dependencies><dependency><groupId>com.atguigu</groupId><artifactId>comment_utils</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- Spring Security依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency></dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>guli_parent</artifactId><groupId>com.atguigu</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>commont</artifactId><packaging>pom</packaging><modules><module>service_base</module><module>comment_utils</module><module>spring_security</module></modules><dependencies><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>provided </scope></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><scope>provided </scope></dependency><!--lombok用来简化实体类:需要安装lombok插件--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided </scope></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><scope>provided </scope></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><scope>provided </scope></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency>--></dependencies></project>

4.7 jwt

package com.atguigu.commonutils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;
import java.util.Date;/*** @author helen* @since 2019/10/16* 生成字符串,包含用户信息,* jwt生成包含三部分:1头2.有效荷载3.签名哈希 防伪标志*/
public class JwtUtils {public static final long EXPIRE = 1000 * 60 * 60 * 24;//token过期时间public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";//密钥public static String getJwtToken(String id, String nickname){String JwtToken = Jwts.builder()//第一步分.setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")//第二部分.setSubject("guli-user").setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRE))//第三部分  token主体.claim("id", id).claim("nickname", nickname).signWith(SignatureAlgorithm.HS256, APP_SECRET).compact();return JwtToken;}/*** 判断token是否存在与有效* @param jwtToken* @return*/public static boolean checkToken(String jwtToken) {if(StringUtils.isEmpty(jwtToken)) return false;try {Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 判断token是否存在与有效* @param request* @return*/public static boolean checkToken(HttpServletRequest request) {try {String jwtToken = request.getHeader("token");System.out.println("jwtToken"+jwtToken);if(StringUtils.isEmpty(jwtToken)) return false;Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 根据token获取会员id* @param request* @return*/public static String getMemberIdByJwtToken(HttpServletRequest request) {String jwtToken = request.getHeader("token");if(StringUtils.isEmpty(jwtToken))return "";Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);Claims claims = claimsJws.getBody();System.out.println("claims:"+claims);return (String)claims.get("id");}
}

4.8 MD5

package com.atguigu.commonutils;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public final class MD5 {public static String encrypt(String strSrc) {try {char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f' };byte[] bytes = strSrc.getBytes();MessageDigest md = MessageDigest.getInstance("MD5");md.update(bytes);bytes = md.digest();System.out.println("bytes"+bytes);int j = bytes.length;System.out.println("j"+j);char[] chars = new char[j * 2];int k = 0;for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];System.out.println(" bytes[i]"+ bytes[i]);//转化hexCharschars[k++] = hexChars[b >>> 4 & 0xf];chars[k++] = hexChars[b & 0xf];}return new String(chars);} catch (NoSuchAlgorithmException e) {e.printStackTrace();throw new RuntimeException("MD5加密出错!!+" + e);}}public static void main(String[] args) {System.out.println(MD5.encrypt("111111"));}}

4.9 R

package com.atguigu.commonutils;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.HashMap;
import java.util.Map;@Data
public class R {@ApiModelProperty(value = "是否成功")private Boolean success;@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")private Map<String, Object> data = new HashMap<String, Object>();//构造器私有化private R() {}//成功静态方法public static R ok() {R r = new R();r.setSuccess(true);r.setCode(ResultCode.SUCCESS);r.setMessage("成功");return r;}//失败静态方法public static R error() {R r = new R();r.setSuccess(false);r.setCode(ResultCode.ERROR);r.setMessage("失败");return r;}public R success(Boolean success) {this.setSuccess(success);return this;}public R message(String message) {this.setMessage(message);return this;}public R code(Integer code) {this.setCode(code);return this;}public R data(String key, Object value) {this.data.put(key, value);return this;}public R data(Map<String, Object> map) {this.setData(map);return this;}
}

Gateway 整合 Spring Security鉴权相关推荐

  1. spring security鉴权

    1.SpringSecurity 鉴权 - [重点] RBAC 基于角色访问控制 Role-Based Access Control组成部分:RBAC模型里面,有3个基础组成部分,分别是:用户user ...

  2. Spring Cloud Gateway 整合Spring Security

    做了一个Spring Cloud项目,网关采用 Spring Cloud Gateway,想要用 Spring Security 进行权限校验,由于 Spring Cloud Gateway 采用 w ...

  3. Spring Security 鉴权流程

    如果对该文章感兴趣欢迎关注我的小博客 Forest,我会分享更多学习时遇到的知识 (●'◡'●) 参考资料 SpringSecurity原理剖析与权限系统设计 SpringSecurity动态鉴权流程 ...

  4. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离

    在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与权限管理. ...

  5. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  6. SpringBoot整合Spring Security【超详细教程】

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Lee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Security是一个 ...

  7. 认证与授权流程与spring boot整合 spring security(1)

    一   spring security 1.1 spring security的作用 Spring Security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截 ...

  8. spring boot整合spring security笔记

    最近自己做了一个小项目,正在进行springboot和spring Security的整合,有一丢丢的感悟,在这里分享一下: 首先,spring boot整合spring security最好是使用T ...

  9. 八、springboot整合Spring Security

    springboot整合Spring Security 简介 Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架.它是保护基于Spring的应用程序的事实标准. Spr ...

最新文章

  1. mysql 相除 取整数位,psql除法保留小数,实现向上取整和向下取整操作_PostgreSQL_数据库...
  2. java枚举可以int值不_java – 如何通过int值迭代枚举?
  3. 【转】Docker 运行时资源限制-内存memory、交换机分区Swap、CPU
  4. linux 日期 通配符,Linux常用基础命令下(grep,history,du,date,通配符,alias,rm,mv,cp)
  5. python 替换array中的值_利用Python提取视频中的字幕(文字识别)
  6. 管理多个Java安装
  7. 保险营销观察报告:保险直播“带货”的现状、风险分析与未来研判
  8. JBPM与设计模式之职责链模式
  9. 如何在Linux上运行Windows软件?
  10. 邮件 自动打印 linux,Linux打印文件和发送邮件
  11. ADO.Net之SqlConnection、 Sqlcommand的应用(读书笔记1)
  12. java多线程方式轮询,深入理解JAVA多线程之线程间的通信方式
  13. 用户在登录的时候,密码输入错误也能登录问题
  14. 【转】Objective-C 属性特性(assign , retain , copy , readonly , readwrite , atomic , nonatomic)...
  15. CAPL脚本如何实现TCP Socket通信
  16. 图像处理的边缘和纹理的区别
  17. cmd命令查询电脑序列号_如何查看台式电脑序列号
  18. 八猴渲染器4.0基本使用教程及渲染教程
  19. 审计工作存在的难点和问题_浅谈审计整改工作存在的困难及对策
  20. python 判断字符串中的的起始、终止子字符串

热门文章

  1. java源代码位置_Java源代码放置位置?
  2. a76比a73强多少_OPPO A79和OPPO A73买哪个好?OPPO A73和OPPO A79对比评测
  3. Custom Control进行多行列表控制CMultilineList类
  4. 2023年TikTok网红营销:从短视频到直播,多维度提升品牌价值
  5. Linux 解决userdel无法删除用户
  6. u盘安装成功计算机里找不到文件夹,u盘里的文件不见了,详细教您U盘内容不显示怎么办...
  7. java math.log10_Java Math log10() 使用方法及示例
  8. html5 canvas 图片变形,HTML5/Canvas 流动的变形圆形
  9. 企业品牌推广随着时代不断改变
  10. 半年使用静电容键盘的感受(宁芝)