SpringSecurity最新版本使用总结

SpringSecurity使用总结:

1、Springsecurity目前问题:

网上的教程大部分都是基于之前的版本,使用的是已经抛弃的继承WebSecurityConfigurerAdapter这个类进行SpringSecurity配置,但是新版本的SpringSecurity已经弃用了WebSecurityConfigurerAdapter这个类,以前的方法依旧可以使用,但是官方并不推荐使用这种方式

这点在官网也可以看到

​ https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter

官方文档说的是:

To assist with the transition to this new style of configuration, we have compiled a list of common use-cases and the suggested alternatives going forward.

In the examples below we follow best practice by using the Spring Security lambda DSL and the method HttpSecurity#authorizeHttpRequests to define our authorization rules. If you are new to the lambda DSL you can read about it in this blog post. If you would like to learn more about why we choose to use HttpSecurity#authorizeHttpRequests you can check out the reference documentation.

翻译过来就是

在 Spring Security 5.7.0-M2 中,我们弃用WebSecurityConfigurerAdapter,因为我们鼓励用户转向基于组件的安全配置为了帮助过渡到这种新的配置方式,我们编制了一份常见用例列表和建议的替代方案。

在下面的示例中,我们遵循最佳实践,使用 Spring Security lambda DSL 和方法HttpSecurity#authorizeHttpRequests来定义我们的授权规则。如果您是 lambda DSL 的新手,您可以阅读这篇博文。如果您想详细了解我们选择使用HttpSecurity#authorizeHttpRequests的原因,可以查看参考文档

1.1、什么是Spring Security lambda DSL ?

https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html

我依旧推荐大家去官网查看,看不懂可以用翻译。

在之前的版本中 我们更加常用的方式是覆盖重写configure(HttpSecurity http)方法,例如:

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Override
        protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .mvcMatchers("/index").permitAll()
                .anyRequest().authenticated()
                .and().formLogin();
    }
}

而现版本推荐声明SecurityFilterChain而不是使用authorizeRequests,例如:

@Bean
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().authenticated();
        )
        // ...

    return http.build();
}

这里不多赘述原理 如果大家很感兴趣的话,我可以专门出一个专栏给大家讲解原理,从基础到新版本的区别

本文章更多在于配置

2、首先登陆成功配置

package org.zhang.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import java.io.IOException;

public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException,  IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=UTF-8");
        ResultBody error = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);
        String s = new ObjectMapper().writeValueAsString(error);
        response.getWriter().println(s);
    }
}

3、登陆失败配置

package org.zhang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FailHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        ResultBody result = null;
        if (e instanceof AccountExpiredException)
        {
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0230);
        }else if (e instanceof BadCredentialsException){
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0210);
        }else if (e instanceof CredentialsExpiredException){
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0202);
        }else if (e instanceof InternalAuthenticationServiceException){
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0201);
        }else{
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0220);
        }

        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
    }
}

这里面的ReusltBody是我自定义的统一返回数据类型,大家可以百度,也可以使用Map简单放回

4、注销成功配置

package org.zhang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

//注销成功
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("msg", "注销成功");
        result.put("status", 200);
        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
    }
}

5、认证入口点配置

package org.zhang.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import java.io.IOException;

public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException,  IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=UTF-8");
        ResultBody error = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);
        String s = new ObjectMapper().writeValueAsString(error);
        response.getWriter().println(s);
    }
}

6、JWT认证配置

package org.zhang.config;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.ObjectUtils;
import org.zhang.utils.JwtUtils;

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.HashMap;

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获取请求的Token
        String token = request.getHeader("Authorization");
        //没有直接跳过
        if (ObjectUtils.isEmpty(token))
        {
            chain.doFilter(request,response);
            return;
        }
        //将token中的用户名和权限用户组放入Authentication对象,在之后实现鉴权
        SecurityContextHolder.getContext().setAuthentication(getAuthentication(token));
        super.doFilterInternal(request, response, chain);
    }
    //解析token获取用户信息
    private UsernamePasswordAuthenticationToken getAuthentication(String token)
    {
        HashMap<String, Object> tokenInfo = JwtUtils.decode(token);
        if(ObjectUtils.isEmpty(tokenInfo)){
            return null;
        }
        String username = (String) tokenInfo.get("username");
        String[] roles = (String[]) tokenInfo.get("roles");
        ArrayList<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for(String role:roles){
            authorities.add(new SimpleGrantedAuthority(role));
        }
        return new UsernamePasswordAuthenticationToken(username,null,authorities);
    }
}

7、重写登陆配置(为了解决前端传值为Json类型)

package org.zhang.config;

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
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 org.zhang.pojo.User;

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.HashMap;
import java.util.Map;

public class LoginFilter extends UsernamePasswordAuthenticationFilter{
    //登陆认证接口
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        //判断是否为Post请求
        if(!request.getMethod().equals("POST"))
        {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //判断认证数据是否为Json 如果登陆数据为JSON 进行JSON处理
        if(request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE))
        {
            Map<String,String> loginData = new HashMap<>();
            try
            {
                //将Json数据转换为Map
                loginData = new ObjectMapper().readValue(request.getInputStream(),Map.class);
            }catch (IOException e)
            {
                throw new RuntimeException(e);
            }
            String username = loginData.get(getUsernameParameter());
            String password = loginData.get(getPasswordParameter());
            if (username == null)
            {
                throw new AuthenticationServiceException("用户名不能为空");
            }
            if (password == null)
            {
                throw new AuthenticationServiceException("密码不能为空");
            }
            UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }else
        {
            //普通表单提交数据处理
            String username = this.obtainUsername(request);
            String password = this.obtainPassword(request);
            if (username == null)
            {
                username = "";
            }
            if (password == null)
            {
                password = "";
            }
            username = username.trim();
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,password);
            this.setDetails(request,authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }


}

7、SpringSecurity核心配置:

package org.zhang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;
import org.zhang.service.impl.UserServiceImpl;


import java.util.Arrays;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Autowired
    private UserServiceImpl userService;


     /**
      * 获取AuthenticationManager(认证管理器),登录时认证使用
     * @param AuthenticationConfiguration
     * @return
      * @throws Exception
     */

    @Bean(name = "authenticationManager")
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authz)->
                        authz
                                .antMatchers("/root/doLogin").permitAll()
                                .antMatchers("/user/userLogin").permitAll()
                                .antMatchers("/film/**").permitAll()
                                .antMatchers("/order/queryTodayMarket").permitAll()
                                .anyRequest().authenticated())
                .logout(logout->
                        logout
                                .logoutSuccessHandler(new MyLogoutSuccessHandler()))
                .cors(cors->
                        cors
                                .configurationSource(configurationSource()))
                .httpBasic(withDefaults())
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()//异常处理
                .authenticationEntryPoint((request, response, e) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    ResultBody error = ResultBody.error("401", "尚未认证,请进行认证操作!");
                    response.getWriter().write(new ObjectMapper().writeValueAsString(error));
                })
                .accessDeniedHandler((request, response, e) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    ResultBody s = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0301);
                    response.getWriter().write(new ObjectMapper().writeValueAsString(s));
                })
                .and()
                .csrf().disable(); //前后端分离没有Session 不需要开启csrf

        http.addFilterAt(loginFilter(http.getSharedObject(AuthenticationManager.class)),UsernamePasswordAuthenticationFilter.class);
        http.addFilter(jwtAuthorizationFilter(http.getSharedObject(AuthenticationManager.class)));
        return http.build();
    }

    //过滤静态资源
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer(){
        return (web)-> web.ignoring().antMatchers("/static/css");
    }


    // 注入登陆过滤器
    @Bean
    public LoginFilter loginFilter(AuthenticationManager authenticationManager) throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        loginFilter.setFilterProcessesUrl("/root/doLogin");
        loginFilter.setUsernameParameter("username");
        loginFilter.setPasswordParameter("password");
        loginFilter.setAuthenticationManager(authenticationManager);
        loginFilter.setAuthenticationSuccessHandler(new SuccessHandler());
        loginFilter.setAuthenticationFailureHandler(new FailHandler());
        return loginFilter;
    }

    //加入token验证过滤器
    @Bean
    public JWTAuthorizationFilter jwtAuthorizationFilter(AuthenticationManager authenticationManager){
        JWTAuthorizationFilter filter = new JWTAuthorizationFilter(authenticationManager);
        return filter;
    }


    //springsecurity跨域
    CorsConfigurationSource configurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }
}
```# SpringSecurity使用总结:

## 1Springsecurity目前问题:

>网上的教程大部分都是基于之前的版本,使用的是已经抛弃的继承WebSecurityConfigurerAdapter这个类进行SpringSecurity配置,但是新版本的SpringSecurity已经弃用了WebSecurityConfigurerAdapter这个类,以前的方法依旧可以使用,但是官方并不推荐使用这种方式
>
>这点在官网也可以看到

​	https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter

官方文档说的是:

To assist with the transition to this new style of configuration, we have compiled a list of common use-cases and the suggested alternatives going forward.

In the examples below we follow best practice by using the Spring Security lambda DSL and the method `HttpSecurity#authorizeHttpRequests` to define our authorization rules. If you are new to the lambda DSL you can read about it in [this blog post](https://spring.io/blog/2019/11/21/spring-security-lambda-dsl). If you would like to learn more about why we choose to use `HttpSecurity#authorizeHttpRequests` you can check out the [reference documentation](https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html).

翻译过来就是

在 Spring Security 5.7.0-M2 中,我们[弃用](https://translate.google.com/website?sl=auto&tl=zh-CN&hl=zh-CN&client=webapp&u=https://github.com/spring-projects/spring-security/issues/10822)了`WebSecurityConfigurerAdapter`,因为我们鼓励用户转向基于组件的安全配置为了帮助过渡到这种新的配置方式,我们编制了一份常见用例列表和建议的替代方案。

在下面的示例中,我们遵循最佳实践,使用 Spring Security lambda DSL 和方法`HttpSecurity#authorizeHttpRequests`来定义我们的授权规则。如果您是 lambda DSL 的新手,您可以阅读[这篇博](https://spring-io.translate.goog/blog/2019/11/21/spring-security-lambda-dsl?_x_tr_sl=auto&_x_tr_tl=zh-CN&_x_tr_hl=zh-CN&_x_tr_pto=wapp)文。如果您想详细了解我们选择使用`HttpSecurity#authorizeHttpRequests`的原因,可以查看[参考文档](https://translate.google.com/website?sl=auto&tl=zh-CN&hl=zh-CN&client=webapp&u=https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html)。

### 1.1、什么是Spring Security lambda DSL ?

https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html

我依旧推荐大家去官网查看,看不懂可以用翻译。

在之前的版本中 我们更加常用的方式是覆盖重写configure(HttpSecurity http)方法,例如:

```java
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Override
        protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .mvcMatchers("/index").permitAll()
                .anyRequest().authenticated()
                .and().formLogin();
    }
}

而现版本推荐声明SecurityFilterChain而不是使用authorizeRequests,例如:

@Bean
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().authenticated();
        )
        // ...

    return http.build();
}

这里不多赘述原理 如果大家很感兴趣的话,我可以专门出一个专栏给大家讲解原理,从基础到新版本的区别

本文章更多在于配置

2、首先登陆成功配置

package org.zhang.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import java.io.IOException;

public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException,  IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=UTF-8");
        ResultBody error = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);
        String s = new ObjectMapper().writeValueAsString(error);
        response.getWriter().println(s);
    }
}

3、登陆失败配置

package org.zhang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FailHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        ResultBody result = null;
        if (e instanceof AccountExpiredException)
        {
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0230);
        }else if (e instanceof BadCredentialsException){
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0210);
        }else if (e instanceof CredentialsExpiredException){
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0202);
        }else if (e instanceof InternalAuthenticationServiceException){
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0201);
        }else{
            result = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0220);
        }

        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
    }
}

这里面的ReusltBody是我自定义的统一返回数据类型,大家可以百度,也可以使用Map简单放回

4、注销成功配置

package org.zhang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

//注销成功
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("msg", "注销成功");
        result.put("status", 200);
        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
    }
}

5、认证入口点配置

package org.zhang.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import java.io.IOException;

public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException,  IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=UTF-8");
        ResultBody error = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);
        String s = new ObjectMapper().writeValueAsString(error);
        response.getWriter().println(s);
    }
}

6、JWT认证配置

package org.zhang.config;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.ObjectUtils;
import org.zhang.utils.JwtUtils;

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.HashMap;

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获取请求的Token
        String token = request.getHeader("Authorization");
        //没有直接跳过
        if (ObjectUtils.isEmpty(token))
        {
            chain.doFilter(request,response);
            return;
        }
        //将token中的用户名和权限用户组放入Authentication对象,在之后实现鉴权
        SecurityContextHolder.getContext().setAuthentication(getAuthentication(token));
        super.doFilterInternal(request, response, chain);
    }
    //解析token获取用户信息
    private UsernamePasswordAuthenticationToken getAuthentication(String token)
    {
        HashMap<String, Object> tokenInfo = JwtUtils.decode(token);
        if(ObjectUtils.isEmpty(tokenInfo)){
            return null;
        }
        String username = (String) tokenInfo.get("username");
        String[] roles = (String[]) tokenInfo.get("roles");
        ArrayList<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for(String role:roles){
            authorities.add(new SimpleGrantedAuthority(role));
        }
        return new UsernamePasswordAuthenticationToken(username,null,authorities);
    }
}

7、重写登陆配置(为了解决前端传值为Json类型)

package org.zhang.config;

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
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 org.zhang.pojo.User;

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.HashMap;
import java.util.Map;

public class LoginFilter extends UsernamePasswordAuthenticationFilter{
    //登陆认证接口
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        //判断是否为Post请求
        if(!request.getMethod().equals("POST"))
        {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //判断认证数据是否为Json 如果登陆数据为JSON 进行JSON处理
        if(request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE))
        {
            Map<String,String> loginData = new HashMap<>();
            try
            {
                //将Json数据转换为Map
                loginData = new ObjectMapper().readValue(request.getInputStream(),Map.class);
            }catch (IOException e)
            {
                throw new RuntimeException(e);
            }
            String username = loginData.get(getUsernameParameter());
            String password = loginData.get(getPasswordParameter());
            if (username == null)
            {
                throw new AuthenticationServiceException("用户名不能为空");
            }
            if (password == null)
            {
                throw new AuthenticationServiceException("密码不能为空");
            }
            UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }else
        {
            //普通表单提交数据处理
            String username = this.obtainUsername(request);
            String password = this.obtainPassword(request);
            if (username == null)
            {
                username = "";
            }
            if (password == null)
            {
                password = "";
            }
            username = username.trim();
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,password);
            this.setDetails(request,authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }


}

7、SpringSecurity核心配置:

package org.zhang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.zhang.comont.AliErrorCodeEnum;
import org.zhang.comont.ResultBody;
import org.zhang.service.impl.UserServiceImpl;


import java.util.Arrays;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Autowired
    private UserServiceImpl userService;


     /**
      * 获取AuthenticationManager(认证管理器),登录时认证使用
     * @param AuthenticationConfiguration
     * @return
      * @throws Exception
     */

    @Bean(name = "authenticationManager")
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authz)->
                        authz
                                .antMatchers("/root/doLogin").permitAll()
                                .antMatchers("/user/userLogin").permitAll()
                                .antMatchers("/film/**").permitAll()
                                .antMatchers("/order/queryTodayMarket").permitAll()
                                .anyRequest().authenticated())
                .logout(logout->
                        logout
                                .logoutSuccessHandler(new MyLogoutSuccessHandler()))
                .cors(cors->
                        cors
                                .configurationSource(configurationSource()))
                .httpBasic(withDefaults())
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()//异常处理
                .authenticationEntryPoint((request, response, e) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    ResultBody error = ResultBody.error("401", "尚未认证,请进行认证操作!");
                    response.getWriter().write(new ObjectMapper().writeValueAsString(error));
                })
                .accessDeniedHandler((request, response, e) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    ResultBody s = ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0301);
                    response.getWriter().write(new ObjectMapper().writeValueAsString(s));
                })
                .and()
                .csrf().disable(); //前后端分离没有Session 不需要开启csrf

        http.addFilterAt(loginFilter(http.getSharedObject(AuthenticationManager.class)),UsernamePasswordAuthenticationFilter.class);
        http.addFilter(jwtAuthorizationFilter(http.getSharedObject(AuthenticationManager.class)));
        return http.build();
    }

    //过滤静态资源
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer(){
        return (web)-> web.ignoring().antMatchers("/static/css");
    }


    // 注入登陆过滤器
    @Bean
    public LoginFilter loginFilter(AuthenticationManager authenticationManager) throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        loginFilter.setFilterProcessesUrl("/root/doLogin");
        loginFilter.setUsernameParameter("username");
        loginFilter.setPasswordParameter("password");
        loginFilter.setAuthenticationManager(authenticationManager);
        loginFilter.setAuthenticationSuccessHandler(new SuccessHandler());
        loginFilter.setAuthenticationFailureHandler(new FailHandler());
        return loginFilter;
    }

    //加入token验证过滤器
    @Bean
    public JWTAuthorizationFilter jwtAuthorizationFilter(AuthenticationManager authenticationManager){
        JWTAuthorizationFilter filter = new JWTAuthorizationFilter(authenticationManager);
        return filter;
    }


    //springsecurity跨域
    CorsConfigurationSource configurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }
}
  • 11
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头路上的小强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值