1.自定义MyUsernamePasswordFilter
/**
* 2023/2/26
*
* @author cyh
* 10:30
*/
@Slf4j
public class MyUsernamePasswordFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
// 自定拦截路由
private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/user/login", "POST");
private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
private boolean postOnly = true;
private FormUser user;
public MyUsernamePasswordFilter() {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
}
public MyUsernamePasswordFilter(AuthenticationManager authenticationManager) {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager);
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
log.info("url:" + request.getRequestURI());
// 获取登录表单
getUser(request);
String username = obtainUsername();
username = username != null ? username.trim() : "";
String password = obtainPassword();
password = password != null ? password : "";
MyUsernamePasswordToken authRequest = MyUsernamePasswordToken.unauthenticated(username, password);
this.setDetails(request, authRequest);
this.setContinueChainBeforeSuccessfulAuthentication(false);
return this.getAuthenticationManager().authenticate(authRequest);
}
}
@Nullable
protected String obtainPassword() {
return user.getPassword();
}
@Nullable
protected String obtainUsername() {
return user.getUsername();
}
protected void setDetails(HttpServletRequest request, MyUsernamePasswordToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
public void setUsernameParameter(String usernameParameter) {
Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
this.usernameParameter = usernameParameter;
}
public void setPasswordParameter(String passwordParameter) {
Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
this.passwordParameter = passwordParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getUsernameParameter() {
return this.usernameParameter;
}
public final String getPasswordParameter() {
return this.passwordParameter;
}
/**
* 获取登录用户信息
*
* @param request
* @return
*/
private void getUser(HttpServletRequest request) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
user = objectMapper.readValue(request.getInputStream(), FormUser.class);
log.info("user:" + user.toString());
} catch (Exception e) {
throw new NullPointerException("获取不到登录信息");
}
}
}
@Slf4j
public class MyUsernamePasswordProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
private final MyUserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
public MyUsernamePasswordProvider(MyUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
MyUsernamePasswordToken tokenReq = (MyUsernamePasswordToken) authentication;
String username = tokenReq.getPrincipal().toString();
String password = tokenReq.getCredentials().toString();
LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(username);
if (!passwordEncoder.matches(password, loginUser.getPassword())) {
throw new RuntimeException("账号或者密码错误");
}
// 将权限列表加入MyUsernamePasswordToken
MyUsernamePasswordToken myUsernameAuthenticationToken = MyUsernamePasswordToken.authenticated(loginUser, null, null);
myUsernameAuthenticationToken.setDetails(authentication.getDetails());
return myUsernameAuthenticationToken;
} catch (Exception e) {
e.printStackTrace();
throw new BadCredentialsException(e.getMessage());
}
}
@Override
public boolean supports(Class<?> authentication) {
return (MyUsernamePasswordToken.class.isAssignableFrom(authentication));
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(userDetailsService, "userDetailsService must not be null");
Assert.notNull(userDetailsService, "userDetailsService must not be null");
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
自定义Token
public class MyUsernamePasswordToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 570L;
private final Object principal;
private Object credentials;
public MyUsernamePasswordToken(Object principal, Object credentials) {
super((Collection) null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
public MyUsernamePasswordToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
public static MyUsernamePasswordToken unauthenticated(Object principal, Object credentials) {
return new MyUsernamePasswordToken(principal, credentials);
}
public static MyUsernamePasswordToken authenticated(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
return new MyUsernamePasswordToken(principal, credentials, authorities);
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
super.setAuthenticated(false);
}
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}
自定义UserDetails
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements UserDetails, Serializable {
private static final long serialVersionUID = -53711580203962796L;
private User user;
private List<Long> permissions;
public LoginUser(User user, List<Long> permissions) {
this.user = user;
this.permissions = permissions;
}
private List<SimpleGrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
if (authorities != null) {
return authorities;
}
if (CollUtil.isEmpty(permissions)) {
return null;
}
authorities = permissions.stream().filter(x -> !ObjectUtil.isNull(x)).map(x -> x.toString())
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.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;
}
}
自定义UserDetailsService
@Slf4j
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("userDetails");
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, username);
User user = userMapper.selectOne(wrapper);
if (Objects.isNull(user)) {
throw new UserNotFindException("找不到用户");
}
if (user.getStatus() == 1) {
throw new UserNotFindException("账户已经被禁用");
}
return new LoginUser(user, null);
}
}
6.自定义成功行为
/**
* 2023/2/26
*
* @author cyh
* 15:04
*/
@Slf4j
@Component
public class MyUsernamePasswordSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
RedisTemplate<String, String> redisTemplate;
@Autowired
UserRoleService userRoleService;
@Autowired
IUserService userService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
Long uid = loginUser.getUser().getId();
// 每次登录添加登录ip和时间
// 获取权限列表并返回
User user = loginUser.getUser();
user.setLastLoginTime(LocalDateTime.now().toString());
user.setLoginIp(ServletUtil.getClientIP(request));
userService.updateById(user);
String token = MyJwtUtil.getToken(uid, RequestKey.ADMIN_USER.getKey());
redisTemplate.opsForValue().set(RequestKey.ADMIN_USER.getKey() + "login:" + uid, token, 60 * 60 * 72, TimeUnit.SECONDS);
// TODO redis存放门店列表
// TODO redis存放权限列表
List<Long> permsByUserId = userRoleService.getPermsByUserId(uid);
ResultAuthority resultAuthority = new ResultAuthority(token, permsByUserId);
ResultData<ResultAuthority> ok = ResultData.success("ok", resultAuthority);
response.getWriter().print(JSONUtil.parseObj(ok));
log.info("登录成功:" + authentication.getPrincipal().toString());
}
}
7.自定义错误返回
@Slf4j
public class MyUsernamePasswordErrorHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.info(exception.getMessage());
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.setStatus(200);
ResultData<ResultAuthority> ok = ResultData.fail(500, exception.getMessage());
response.getWriter().print(JSONUtil.parseObj(ok));
}
}
/**
* 2023/3/6
*
* @author cyh
* 9:29
*/
@Slf4j
public class WxLoginFilter extends AbstractAuthenticationProcessingFilter {
private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/wxlogin/userinfo", "GET");
private boolean postOnly = true;
public WxLoginFilter() {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
}
public WxLoginFilter(AuthenticationManager authenticationManager) {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
log.info("正在进行拦截");
if (!request.getMethod().equals("GET")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
// 从请求头里获取到code
String code = obtainCode(request);
code = code != null ? code.trim() : "";
WxUserToken wxUserToken = WxUserToken.unauthenticated(code, null);
this.setDetails(request, wxUserToken);
return this.getAuthenticationManager().authenticate(wxUserToken);
}
}
protected void setDetails(HttpServletRequest request, WxUserToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
@Nullable
protected String obtainCode(HttpServletRequest request) {
return request.getParameter("code");
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
}
微信登录provider
/**
* 2023/3/6
*
* @author cyh
* 9:35
*/
@Slf4j
public class WxLoginProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
private final WxLoginServiceImpl wxLoginService;
private final WxLoginUtilService wxLoginUtilService;
private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
public WxLoginProvider(WxLoginServiceImpl userDetailsService, WxLoginUtilService wxLoginUtilService) {
this.wxLoginService = userDetailsService;
this.wxLoginUtilService = wxLoginUtilService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
WxUserToken tokenReq = (WxUserToken) authentication;
String code = (String) tokenReq.getPrincipal();
WxUserToken wxUserToken = null;
String openid = null;
// 根据code拿到access_token和openid
try {
// 向微信获取
WxOAuth2AccessToken accessToken = wxLoginUtilService.getAccessTokenAndOpenID(code);
openid = wxLoginUtilService.getWxUserInfo(accessToken);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
// 从数据库里获取用户信息并设置认证通过
WxLoginEntity wxLoginEntity = wxLoginService.loadUserByUsername(openid);
log.info("userDetails:{}", wxLoginEntity.toString());
wxUserToken = WxUserToken.authenticated(wxLoginEntity, null, null);
wxUserToken.setDetails(authentication.getDetails());
return wxUserToken;
}
@Override
public boolean supports(Class<?> authentication) {
return (WxUserToken.class.isAssignableFrom(authentication));
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(wxLoginService, "userDetailsService must not be null");
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
}
微信登录的Token
/**
* 2023/3/6
*
* @author cyh
* 9:33
*/
public class WxUserToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 570L;
private final Object principal;
private Object credentials;
public WxUserToken(Object principal, Object credentials) {
super((Collection) null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
public WxUserToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
public static WxUserToken unauthenticated(Object principal, Object credentials) {
return new WxUserToken(principal, credentials);
}
public static WxUserToken authenticated(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
return new WxUserToken(principal, credentials, authorities);
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
super.setAuthenticated(false);
}
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}
/**
* 2023/3/6
*
* @author cyh
* 14:12
*/
@Data
@AllArgsConstructor
public class WxLoginEntity implements UserDetails {
private OrderUser user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return user.getOpenid();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
@Slf4j
@Service
public class WxLoginServiceImpl implements UserDetailsService {
@Autowired
WxLoginUtilService wxLoginUtilService;
@Autowired
IOrderUserService orderUserService;
/**
* 获取数据库用户信息
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public WxLoginEntity loadUserByUsername(String username) throws UsernameNotFoundException {
OrderUser orderUser;
orderUser = orderUserService.getOne(new LambdaQueryWrapper<OrderUser>().eq(OrderUser::getOpenid, username));
if (ObjectUtil.isNull(orderUser)) {
throw new UsernameNotFoundException("找不到用户");
}
return new WxLoginEntity(orderUser);
}
}
成功返回
@Slf4j
@Component
public class WxLoginSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
RedisTemplate<String, String> redisTemplate;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
@IgnoreResponseAdvice
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
// 获取当前认证的用户
WxLoginEntity loginUser = (WxLoginEntity) authentication.getPrincipal();
// 获取用户的id
Long uid = loginUser.getUser().getId();
// 获取token
String token = MyJwtUtil.getToken(uid, RequestKey.WX_USER.getKey());
redisTemplate.opsForValue().set(RequestKey.WX_USER.getKey() + "login:" + loginUser.getUser().getId(), token, 60 * 60 * 72, TimeUnit.SECONDS);
// 设置返回的id和token
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
Map<String, String> map = new HashMap<>();
map.put("nickname", loginUser.getUser().getNickname());
map.put("openid", loginUser.getUser().getOpenid());
map.put("token", token);
// 返回给前端
ResultData<Map> ok = ResultData.success("ok", map);
response.getWriter().print(JSONUtil.parseObj(ok));
}
}
失败返回
/**
* 2023/3/6
*
* @author cyh
* 9:35
*/
public class WxLoginErrorHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
throw new RuntimeException("授权登录验证失败");
}
}
/**
* 2023/2/26
*
* @author cyh
* 17:18
*/
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
/**
* 请求头token的key
*/
private String tokenKey = RequestKey.TOKEN_KEY.getKey();
/**
* 用户的value
*/
private String wxUser = RequestKey.WX_USER.getKey();
/**
* 管理用户的value
*/
private String adminUser = RequestKey.ADMIN_USER.getKey();
/**
* redis 工具
*/
private RedisTemplate<String, String> redisTemplate;
/**
* 微信登录用户
*/
private IOrderUserService orderUserService;
/**
* 管理用户
*/
private IUserService userService;
/**
* jwt 工具
*/
private MyJwtUtil myJwtUtil;
/**
* 用户权限
*/
private UserRoleService userRoleService;
public JwtAuthenticationTokenFilter(IOrderUserService orderUserService, IUserService userService, MyJwtUtil myJwtUtil, UserRoleService userRoleService, RedisTemplate<String, String> redisTemplate) {
this.orderUserService = orderUserService;
this.userService = userService;
this.myJwtUtil = myJwtUtil;
this.userRoleService = userRoleService;
this.redisTemplate = redisTemplate;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String reqToken = request.getHeader(this.tokenKey);
log.info("现在{}正在进行jwt认证:{}", request.getRequestURI(), reqToken);
// 判断token和请求用户是否存在
if (Strings.isBlank(reqToken)) {
chain.doFilter(request, response);
return;
}
// 判断token是否过期
if (!myJwtUtil.verifyToken(reqToken)) {
throw new TokenException("非法token, token已过期");
}
// 从token上获取uid
Long uid = myJwtUtil.getUid(reqToken);
String reqUser = myJwtUtil.getRoleUser(reqToken);
if (ObjectUtil.isNull(uid) || ObjectUtil.isNull(reqUser)) {
throw new TokenException("非法token");
}
if (StrUtil.equals(reqUser, wxUser)) {
// 与redis中的用户token对比
String redisToken = redisTemplate.opsForValue().get(wxUser + "login:" + uid);
log.info("redisToken:{}", redisToken);
if (StrUtil.isBlankIfStr(redisToken) || !StrUtil.equals(redisToken, reqToken)) {
throw new TokenException("非法token");
}
// 判断获取的用户存不存在
OrderUser user = orderUserService.getById(uid);
if (ObjectUtil.isNull(user)) {
throw new TokenException("非法token");
}
// 存在设置认证通过
WxLoginEntity wxLoginEntity = new WxLoginEntity(user);
WxUserToken wxUserToken = WxUserToken.authenticated(wxLoginEntity, null, null);
SecurityContextHolder.getContext().setAuthentication(wxUserToken);
chain.doFilter(request, response);
return;
}
if (StrUtil.equals(reqUser, adminUser)) {
// 与redis中的用户token对比
String redisToken = redisTemplate.opsForValue().get(adminUser + "login:" + uid);
log.info("redisToken:{}", redisToken);
if (StrUtil.isBlankIfStr(redisToken) || !StrUtil.equals(redisToken, reqToken)) {
throw new TokenException("非法token");
}
// TODO 从redis获取用户信息
User byId = userService.getById(uid);
// TODO 将用户信息放入MyUsernamePasswordToken
List<Long> permsByUserId = userRoleService.getPermsByUserId(uid);
LoginUser loginUser = new LoginUser(byId, permsByUserId);
if (loginUser.getUser().getStatus() == 1) {
redisTemplate.delete(adminUser + "login:" + uid);
throw new TokenException("账户被禁用,请重新登录");
}
MyUsernamePasswordToken myUsernamePasswordToken = new MyUsernamePasswordToken(loginUser, null,
loginUser.getAuthorities());
// TODO 将认证的信息放入 SecurityContextHolder.getContext()
SecurityContextHolder.getContext().setAuthentication(myUsernamePasswordToken);
chain.doFilter(request, response);
return;
}
throw new TokenException("非法token");
}
}
@Configuration
@EnableWebSecurity // 添加 security 过滤器\
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
/**
* token认证器
*/
@Autowired
IOrderUserService orderUserService;
@Autowired
IUserService userService;
@Autowired
MyJwtUtil myJwtUtil;
@Autowired
UserRoleService userRoleService;
@Autowired
RedisTemplate<String, String> redisTemplate;
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
return new JwtAuthenticationTokenFilter(orderUserService, userService, myJwtUtil, userRoleService, redisTemplate);
}
/**
* 放行路径配置类
*/
@Autowired
SecurityRelease securityRelease;
/**
* 放行路径
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 获取AuthenticationManager(认证管理器),登录时认证使用
*
* @return
* @throws Exception
*/
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
return authenticationManager;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl());
return
http.authorizeRequests(authorize -> authorize
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 请求放开
.antMatchers(securityRelease.getReleaseUrl()).permitAll()
// 其他地址的访问均需验证权限
.anyRequest().authenticated()
) // 基于 token,不需要 csrf
.csrf().disable()
.formLogin().disable()
// 基于 token,不需要 session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.addFilterAt(wxLoginFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterAt(usernamePasswordFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
.build();
}
/**
* 配置跨源访问(CORS)
*
* @return
*/
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
@Autowired
WxLoginServiceImpl wxLoginService;
@Autowired
WxLoginUtilService wxLoginUtilService;
@Autowired
WxLoginSuccessHandler wxLoginSuccessHandler;
// 添加微信用户登录拦截器
WxLoginFilter wxLoginFilter() throws Exception {
WxLoginFilter myUsernameFilter = new WxLoginFilter();
ProviderManager providerManager = new ProviderManager(Collections.singletonList(wxLoginProvider()));
myUsernameFilter.setAuthenticationManager(providerManager);
myUsernameFilter.setAuthenticationSuccessHandler(wxLoginSuccessHandler);
myUsernameFilter.setAuthenticationFailureHandler(new WxLoginErrorHandler());
myUsernameFilter.setContinueChainBeforeSuccessfulAuthentication(true);
return myUsernameFilter;
}
WxLoginProvider wxLoginProvider() {
WxLoginProvider provider = new WxLoginProvider(wxLoginService, wxLoginUtilService);
return provider;
}
@Autowired
MyUsernamePasswordSuccessHandler myUsernamePasswordSuccessHandler;
@Autowired
MyUserDetailsService userDetailsService;
/**
* 添加用户登录拦截器
*
* @return
*/
MyUsernamePasswordFilter usernamePasswordFilter() {
MyUsernamePasswordFilter filter = new MyUsernamePasswordFilter();
ProviderManager manager = new ProviderManager(Collections.singletonList(usernamePasswordProvider()));
filter.setAuthenticationManager(manager);
filter.setAuthenticationFailureHandler(new MyUsernamePasswordErrorHandler());
filter.setAuthenticationSuccessHandler(myUsernamePasswordSuccessHandler);
return filter;
}
MyUsernamePasswordProvider usernamePasswordProvider() {
return new MyUsernamePasswordProvider(userDetailsService, passwordEncoder());
}
}
my-security:
releaseUrl:
- /wxlogin/**
- /user/login
- /user/logout
- /doc.html
- /webjars/**
- /swagger-resources/**
- /v2/**
- /wx-pay/**
- /**
/**
* 2023/3/13
* security 放行路径配置类
*
* @author cyh
* 14:27
*/
@Configuration
@Data
@ConfigurationProperties(prefix = "my-security")
public class SecurityRelease {
private String[] releaseUrl;
}
数据库权限点保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWa6zeeH-1679449812207)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230322093826605.png)]
登录返回权限点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mb8MtsDm-1679449812208)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230322094029525.png)]
每次请求加载自定义Token并加载权限点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QkccC3If-1679449812209)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230322094147211.png)]
在方法前权限点验证用户权限 — 配置类开启方法级别的权限认证
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hb9Wn6uw-1679449812209)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230322094236312.png)]
自定义权限点的转换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IpMzvhOS-1679449812209)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230322094404170.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zIKK617J-1679449812210)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230322094420956.png)]
rdProvider usernamePasswordProvider() {
return new MyUsernamePasswordProvider(userDetailsService, passwordEncoder());
}
}
### **4.yml** 文件配置放行路径
```java
my-security:
releaseUrl:
- /wxlogin/**
- /user/login
- /user/logout
- /doc.html
- /webjars/**
- /swagger-resources/**
- /v2/**
- /wx-pay/**
- /**
/**
* 2023/3/13
* security 放行路径配置类
*
* @author cyh
* 14:27
*/
@Configuration
@Data
@ConfigurationProperties(prefix = "my-security")
public class SecurityRelease {
private String[] releaseUrl;
}
数据库权限点保存
[外链图片转存中…(img-aWa6zeeH-1679449812207)]
登录返回权限点
[外链图片转存中…(img-Mb8MtsDm-1679449812208)]
每次请求加载自定义Token并加载权限点
[外链图片转存中…(img-QkccC3If-1679449812209)]
在方法前权限点验证用户权限 — 配置类开启方法级别的权限认证
[外链图片转存中…(img-Hb9Wn6uw-1679449812209)]
自定义权限点的转换
[外链图片转存中…(img-IpMzvhOS-1679449812209)]
[外链图片转存中…(img-zIKK617J-1679449812210)]