赞
踩
目录
Spring Security作为当下最流行的认证授权框架,提供了非常全面且完善的认证授权流程,并且通过与Springboot的结合,极大的简化了开发与使用。spring官方也提供了详细的文档和丰富的应用实例。
官方文档:Spring Security
应用实例:https://github.com/thombergs/code-examples/tree/master/spring-security
但在我们的实际开发工作中,我们绝大部分都是前后端分离的项目,作为后端开发人员,我们并不关心前段页面的跳转,此外,大多数前后端业务数据都是通过JSON方式传递的,并不是Spring security 默认的form 格式。以下便是一个简单的通过JSON方式自定义登陆认证的项目简介。
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
spring security 提供了一个实现了DelegatingFilterProxy的Filter,使Servlet container 的生命周期和 Spring’s ApplicationContext建立联系,从而达到通过Filter对web请求进行授权认证,具体流程如下图所示:
在spring security中,所有的filter都被放在SecurityFilterChain中 按照顺序被调用处理web request.
具体的源码解析可以参考:Spring Security (一):自定义登陆_见面说Hello的博客-CSDN博客
因此,要想实现自定义登陆认证,需要自定义Filter,具体项目代码如下所示。
通过JSON方式获取用户名密码
- public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
-
-
- public CustomUsernamePasswordAuthenticationFilter() {
- super();
- }
-
-
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
- if (!request.getMethod().equals("POST") || (!request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE))) {
- throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
- }
- // 2. 判断是否是json格式请求类型
- if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
- try {
- CustomUser customUser = new ObjectMapper().readValue(request.getInputStream(), CustomUser.class);
- String username = customUser.getUsername();
- String password = customUser.getPassword();
- UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
- setDetails(request, authenticationToken);
- return this.getAuthenticationManager().authenticate(authenticationToken);
- } catch (IOException e) {
- throw new AuthenticationServiceException(e.getMessage());
- }
-
- }
- return super.attemptAuthentication(request, response);
- }
- }

- public class CustomAuthenticationManager implements AuthenticationManager {
-
- public CustomAuthenticationManager() {
- super();
- }
-
- private DaoAuthenticationProvider authenticationProvider;
-
- public void setAuthenticationProvider(DaoAuthenticationProvider authenticationProvider) {
- this.authenticationProvider = authenticationProvider;
- }
-
- @Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- return authenticationProvider.authenticate(authentication);
- }
- }

- public class CustomAuthenticationProvider extends DaoAuthenticationProvider {
-
- public CustomAuthenticationProvider() {
- super();
- }
-
- }
这里我为了方便仅构造了一个Map,实际应用中应从数据库获取
- @Service
- public class CustomUserDetailsService implements UserDetailsService {
-
- protected static final Map<String, CustomUser> map = new HashMap<>();
-
- public static Map<String, CustomUser> getMap() {
- return map;
- }
-
- static {
- String pwd = new BCryptPasswordEncoder().encode("userPwd");
- map.put("user", new CustomUser(1L, "user", pwd));
- map.put("admin", new CustomUser(2L, "admin", pwd));
- }
-
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- CustomUser customUser = map.get(username);
- if (customUser == null) {
- throw new UsernameNotFoundException("username " + username + " is not found");
- }
- return new CustomUserDetails(customUser);
- }
-
-
- }

- public class CustomUser implements Serializable {
-
- private Long userId;
-
- private String username;
-
- private String password;
-
- public CustomUser() {
- }
-
-
- public CustomUser(Long userId, String username, String password) {
- this.userId = userId;
- this.username = username;
- this.password = password;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
- }

- public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler {
-
- @Override
- public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
- response.setCharacterEncoding("UTF-8");
- response.setContentType("application/json; charset=utf-8");
- response.setStatus(HttpServletResponse.SC_OK);
- UserDetails customUser = (UserDetails) authentication.getPrincipal();
- String username = customUser.getUsername();
- response.addCookie(new Cookie("username", username));
- WebResponse<String> success = WebResponse.success(username);
- response.getWriter().write(JSON.toJSONString(success));
- }
- }
自定义认证失败Handler
- package com.study.security.config;
-
- import com.alibaba.fastjson.JSON;
- import org.springframework.security.core.AuthenticationException;
- import org.springframework.security.web.authentication.AuthenticationFailureHandler;
-
- import javax.servlet.ServletException;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
-
- /**
- * @author Say Hello
- * @version 1.0.0
- * @Date 2023/7/27
- * @Description
- */
- public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
- @Override
- public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
- response.setCharacterEncoding("UTF-8");
- response.setContentType("application/json; charset=utf-8");
- response.setStatus(HttpServletResponse.SC_OK);
- WebResponse<Object> fail = WebResponse.fail();
- response.getWriter().write(JSON.toJSONString(fail));
- }
- }

- package com.study.security.config;
-
-
- import com.study.security.config.cookie.CustomCookieAuthenticationFilter;
- import com.study.security.config.phone.CustomPhoneAuthenticationManager;
- import com.study.security.config.phone.CustomPhoneAuthenticationProcessingFilter;
- import com.study.security.config.phone.CustomPhoneAuthenticationProvider;
- import com.study.security.service.CustomPhoneDetailsService;
- import com.study.security.service.CustomUserDetailsService;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Primary;
- import org.springframework.core.annotation.Order;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
- import org.springframework.security.config.annotation.web.builders.HttpSecurity;
- import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.security.web.SecurityFilterChain;
- import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-
- import javax.annotation.Resource;
-
- /**
- * @author Say Hello
- * @version 1.0.0
- * @Date 2023/7/26
- * @Description
- */
- @Configuration
- @EnableWebSecurity
- public class SecurityConfig {
-
- @Value("${spring.security.custom.url.login}")
- String loginUrl;
-
- @Resource
- CustomUserDetailsService customUserDetailsService;
-
- @Bean
- public PasswordEncoder customPasswordEncoder() {
- return new BCryptPasswordEncoder();
- }
-
- @Bean
- @Order(1)
- public SecurityFilterChain customSecurityFilterChain(HttpSecurity http) throws Exception {
- http.authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .csrf().disable()
- //向SecurityFilterChain中插入自定以的AuthenticationManager
- .authenticationManager(customAuthenticationManager())
- .authenticationManager(customPhoneAuthenticationManager())
- //向SecurityFilterChain中插入自定以的AuthenticationProvider
- .authenticationProvider(customAuthenticationProvider())
- .authenticationProvider(customPhoneAuthenticationProvider())
- .exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())
- .and()
- .logout().logoutUrl(logoutUrl)
- .logoutSuccessHandler(new CustomLogoutSuccessHandler());
- // 将loginFilter过滤器添加到UsernamePasswordAuthenticationFilter过滤器所在的位置
- http.addFilterAt(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
- return http.build();
- }
-
- @Bean
- public CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter() {
- CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
- //配置登陆认证的入口
- customUsernamePasswordAuthenticationFilter.setFilterProcessesUrl(loginUrl);
- //配置manager
- customUsernamePasswordAuthenticationFilter.setAuthenticationManager(customAuthenticationManager());
- //设置认证成功Handler
- customUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(new CustomLoginSuccessHandler());
- //设置认证失败Handler
- customUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
- return customUsernamePasswordAuthenticationFilter;
- }
-
- @Bean
- public AuthenticationManager customAuthenticationManager() {
- CustomAuthenticationManager customAuthenticationManager = new CustomAuthenticationManager();
- customAuthenticationManager.setAuthenticationProvider(customAuthenticationProvider());
- return customAuthenticationManager;
- }
-
-
- @Bean
- public DaoAuthenticationProvider customAuthenticationProvider() {
- CustomAuthenticationProvider customAuthenticationProvider = new CustomAuthenticationProvider();
- customAuthenticationProvider.setPasswordEncoder(customPasswordEncoder());
- customAuthenticationProvider.setUserDetailsService(customUserDetailsService);
- return customAuthenticationProvider;
- }
-
- }

未登陆访问
认证失败
认证成功
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。