Security 多种方式登录
1.Security 介绍
- 官网链接:https://docs.spring.io/spring-security/reference/5.7.6/servlet/architecture.html
2.Security 自定义拦截器实现多种登录方式
1. 账户密码登录
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("获取不到登录信息");
}
}
}
- 自定义provider
@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));
}
}
3. 微信授权登录
- 微信登录拦截器
/**
* 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;
}
}
- 微信登录的UserDetails
/**
* 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;
}
}
- 微信登录的UserDetailsService
@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("授权登录验证失败"); } }
自定义token拦截器
/** * 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"); } }
4. Security配置类
@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());
}
}
4.yml 文件配置放行路径
my-security:
releaseUrl:
- /wxlogin/**
- /user/login
- /user/logout
- /doc.html
- /webjars/**
- /swagger-resources/**
- /v2/**
- /wx-pay/**
- /**
5. 放行路径配置类
/**
* 2023/3/13
* security 放行路径配置类
*
* @author cyh
* 14:27
*/
@Configuration
@Data
@ConfigurationProperties(prefix = "my-security")
public class SecurityRelease {
private String[] releaseUrl;
}
3. 权限设置
-
数据库权限点保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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/**
- /**
5. 放行路径配置类
/**
* 2023/3/13
* security 放行路径配置类
*
* @author cyh
* 14:27
*/
@Configuration
@Data
@ConfigurationProperties(prefix = "my-security")
public class SecurityRelease {
private String[] releaseUrl;
}
3. 权限设置
-
数据库权限点保存
[外链图片转存中…(img-aWa6zeeH-1679449812207)]
-
登录返回权限点
[外链图片转存中…(img-Mb8MtsDm-1679449812208)]
-
每次请求加载自定义Token并加载权限点
[外链图片转存中…(img-QkccC3If-1679449812209)]
-
在方法前权限点验证用户权限 — 配置类开启方法级别的权限认证
[外链图片转存中…(img-Hb9Wn6uw-1679449812209)]
-
自定义权限点的转换
[外链图片转存中…(img-IpMzvhOS-1679449812209)]
[外链图片转存中…(img-zIKK617J-1679449812210)]