SpringSecurity6.x变了很多写法。
在编写多种登录方式的时候,网上大多是5.x的,很多类都没了。
以下是SpringSecurity6.x多种登录方式的写法。
目录
4. 配置SecurityConfiguration,把上边的两个 登录过滤器加到过滤器链中。
1. 编写第一种登录-账号密码json登录方式
package com.hw.mo.security.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hw.mo.captcha.config.CaptchaConfig;
import com.hw.mo.security.entity.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
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 java.io.IOException;
/**
* @author : guanzheng
* @date : 2023/6/26 15:17
*/
public class JsonLoginFilter extends UsernamePasswordAuthenticationFilter {
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String contentType = request.getContentType();
if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType) || MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(contentType)) {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = null;
String password = null;
try {
LoginUser user = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
username = user.getUsername();
username = (username != null) ? username.trim() : "";
password = user.getPassword();
password = (password != null) ? password : "";
} catch (IOException e) {
throw new RuntimeException(e);
}
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
return super.attemptAuthentication(request,response);
}
}
2. 编写第二种登录方式-手机验证码登录
package com.hw.mo.security.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hw.mo.security.domain.PhoneCodeLoginAuthticationToken;
import com.hw.mo.security.entity.LoginUser;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import java.io.IOException;
public class PhoneCodeLoginFilter extends AbstractAuthenticationProcessingFilter {
public PhoneCodeLoginFilter() {
super(new AntPathRequestMatcher("/loginPhoneCode","POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
// 需要是 POST 请求
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
// 判断请求格式是否 JSON
if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
LoginUser user = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
// 获得请求参数
String username = user.getUsername();
String phoneCode = user.getPhoneCode();
String captchaUuid = user.getCaptchaUuid();
//TODO 检查验证码是否正确
if (CaptchaUtil.validate(captchaUuid,phoneCode).isOk()){
}
/**
* 使用请求参数传递的邮箱和验证码,封装为一个未认证 EmailVerificationCodeAuthenticationToken 身份认证对象,
* 然后将该对象交给 AuthenticationManager 进行认证
*/
PhoneCodeLoginAuthticationToken token = new PhoneCodeLoginAuthticationToken(username);
setDetails(request, token);
return this.getAuthenticationManager().authenticate(token);
}
return null;
}
public void setDetails(HttpServletRequest request , PhoneCodeLoginAuthticationToken token){
token.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
}
3. 编写验证码登录处理器
package com.hw.mo.security.provider;
import com.hw.mo.security.domain.PhoneCodeLoginAuthticationToken;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
@Component
public class PhoneCodeLoginProvider implements AuthenticationProvider {
UserDetailsService userDetailsService;
public PhoneCodeLoginProvider(UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.isAuthenticated()) {
return authentication;
}
//获取过滤器封装的token信息
PhoneCodeLoginAuthticationToken authenticationToken = (PhoneCodeLoginAuthticationToken) authentication;
String username = (String)authenticationToken.getPrincipal();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 不通过
if (userDetails == null) {
throw new BadCredentialsException("用户不存在");
}
// 根用户拥有全部的权限
PhoneCodeLoginAuthticationToken authenticationResult = new PhoneCodeLoginAuthticationToken(userDetails, null);
return authenticationResult;
}
@Override
public boolean supports(Class<?> authentication) {
return PhoneCodeLoginAuthticationToken.class.isAssignableFrom(authentication);
}
}
4. 配置SecurityConfiguration,把上边的两个 登录过滤器加到过滤器链中。
package com.hw.mo.security.config;
import com.hw.mo.security.filter.JsonLoginFilter;
import com.hw.mo.security.filter.JwtAuthenticationFilter;
import com.hw.mo.security.filter.PhoneCodeLoginFilter;
import com.hw.mo.security.handler.*;
import com.hw.mo.security.provider.PhoneCodeLoginProvider;
import com.hw.mo.security.service.impl.LoginUserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @author : guanzheng
* @date : 2023/6/25 9:03
*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Autowired
LoginUserDetailServiceImpl userDetailService;
@Autowired
MoPasswordEncoder passwordEncoder;
@Autowired
PhoneCodeLoginProvider phoneCodeLoginProvider;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize)->
authorize
.requestMatchers("/rongyan/**","/login*","/captcha*","/register*").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(e-> {
e.accessDeniedHandler(new MyAccessDeniedHandler());
e.authenticationEntryPoint(new AuthenticatedErrorHandler());
})
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.disable())
;
return http.build();
}
/**
* 加载账号密码json登录
*/
@Bean
JsonLoginFilter myJsonLoginFilter(HttpSecurity http) throws Exception {
JsonLoginFilter myJsonLoginFilter = new JsonLoginFilter();
//自定义登录url
myJsonLoginFilter.setFilterProcessesUrl("/login");
myJsonLoginFilter.setAuthenticationSuccessHandler(new LoginSuccessHandler());
myJsonLoginFilter.setAuthenticationFailureHandler(new LoginFailureHandler());
myJsonLoginFilter.setAuthenticationManager(authenticationManager(http));
return myJsonLoginFilter;
}
/**
* 加载手机验证码登录
*/
@Bean
PhoneCodeLoginFilter phoneCodeLoginFilter(HttpSecurity http) throws Exception {
PhoneCodeLoginFilter phoneCodeLoginFilter = new PhoneCodeLoginFilter();
//自定义登录url
phoneCodeLoginFilter.setFilterProcessesUrl("/loginPhoneCode");
phoneCodeLoginFilter.setAuthenticationSuccessHandler(new LoginSuccessHandler());
phoneCodeLoginFilter.setAuthenticationFailureHandler(new LoginFailureHandler());
phoneCodeLoginFilter.setAuthenticationManager(authenticationManager(http));
return phoneCodeLoginFilter;
}
@Bean
AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
//设置用户信息处理器
daoAuthenticationProvider.setUserDetailsService(userDetailService);
//设置密码处理器
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(phoneCodeLoginProvider);//自定义的
authenticationManagerBuilder.authenticationProvider(daoAuthenticationProvider);//原来默认的
return authenticationManagerBuilder.build();
}
}