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)方法,例如:
@ConfigurationpublicclassWebSecurityConfigurerextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
http.authorizeHttpRequests().mvcMatchers("/index").permitAll().anyRequest().authenticated().and().formLogin();}}
而现版本推荐声明SecurityFilterChain而不是使用authorizeRequests,例如:
@BeanSecurityFilterChainweb(HttpSecurity http)throwsAuthenticationException{
http
.authorizeHttpRequests((authorize)-> authorize
.anyRequest().authenticated();)// ...return http.build();}
这里不多赘述原理 如果大家很感兴趣的话,我可以专门出一个专栏给大家讲解原理,从基础到新版本的区别
本文章更多在于配置
2、首先登陆成功配置
packageorg.zhang.config;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.http.HttpStatus;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.AuthenticationEntryPoint;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.xml.transform.Result;importjava.io.IOException;publicclassMyAuthenticationEntryPointimplementsAuthenticationEntryPoint{@Overridepublicvoidcommence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)throwsIOException,IOException{
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");ResultBody error =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);String s =newObjectMapper().writeValueAsString(error);
response.getWriter().println(s);}}
3、登陆失败配置
packageorg.zhang.config;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.security.authentication.AccountExpiredException;importorg.springframework.security.authentication.BadCredentialsException;importorg.springframework.security.authentication.CredentialsExpiredException;importorg.springframework.security.authentication.InternalAuthenticationServiceException;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.authentication.AuthenticationFailureHandler;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;publicclassFailHandlerimplementsAuthenticationFailureHandler{@OverridepublicvoidonAuthenticationFailure(HttpServletRequest request,HttpServletResponse response,AuthenticationException e)throwsIOException,ServletException{ResultBody result =null;if(e instanceofAccountExpiredException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0230);}elseif(e instanceofBadCredentialsException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0210);}elseif(e instanceofCredentialsExpiredException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0202);}elseif(e instanceofInternalAuthenticationServiceException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0201);}else{
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0220);}
response.setContentType("application/json;charset=UTF-8");String s =newObjectMapper().writeValueAsString(result);
response.getWriter().println(s);}}
这里面的ReusltBody是我自定义的统一返回数据类型,大家可以百度,也可以使用Map简单放回
4、注销成功配置
packageorg.zhang.config;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.security.core.Authentication;importorg.springframework.security.web.authentication.logout.LogoutSuccessHandler;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.HashMap;importjava.util.Map;//注销成功publicclassMyLogoutSuccessHandlerimplementsLogoutSuccessHandler{@OverridepublicvoidonLogoutSuccess(HttpServletRequest request,HttpServletResponse response,Authentication authentication)throwsIOException,ServletException{Map<String,Object> result =newHashMap<String,Object>();
result.put("msg","注销成功");
result.put("status",200);
response.setContentType("application/json;charset=UTF-8");String s =newObjectMapper().writeValueAsString(result);
response.getWriter().println(s);}}
5、认证入口点配置
packageorg.zhang.config;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.http.HttpStatus;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.AuthenticationEntryPoint;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.xml.transform.Result;importjava.io.IOException;publicclassMyAuthenticationEntryPointimplementsAuthenticationEntryPoint{@Overridepublicvoidcommence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)throwsIOException,IOException{
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");ResultBody error =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);String s =newObjectMapper().writeValueAsString(error);
response.getWriter().println(s);}}
6、JWT认证配置
packageorg.zhang.config;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.authority.SimpleGrantedAuthority;importorg.springframework.security.core.context.SecurityContextHolder;importorg.springframework.security.web.authentication.www.BasicAuthenticationFilter;importorg.springframework.util.ObjectUtils;importorg.zhang.utils.JwtUtils;importjavax.servlet.FilterChain;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.ArrayList;importjava.util.HashMap;publicclassJWTAuthorizationFilterextendsBasicAuthenticationFilter{publicJWTAuthorizationFilter(AuthenticationManager authenticationManager){super(authenticationManager);}@OverrideprotectedvoiddoFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain)throwsIOException,ServletException{//获取请求的TokenString 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获取用户信息privateUsernamePasswordAuthenticationTokengetAuthentication(String token){HashMap<String,Object> tokenInfo =JwtUtils.decode(token);if(ObjectUtils.isEmpty(tokenInfo)){returnnull;}String username =(String) tokenInfo.get("username");String[] roles =(String[]) tokenInfo.get("roles");ArrayList<SimpleGrantedAuthority> authorities =newArrayList<>();for(String role:roles){
authorities.add(newSimpleGrantedAuthority(role));}returnnewUsernamePasswordAuthenticationToken(username,null,authorities);}}
7、重写登陆配置(为了解决前端传值为Json类型)
packageorg.zhang.config;importcom.fasterxml.jackson.core.exc.StreamReadException;importcom.fasterxml.jackson.databind.DatabindException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.MediaType;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.authentication.AuthenticationServiceException;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.Authentication;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.zhang.pojo.User;importjavax.servlet.FilterChain;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.HashMap;importjava.util.Map;publicclassLoginFilterextendsUsernamePasswordAuthenticationFilter{//登陆认证接口@OverridepublicAuthenticationattemptAuthentication(HttpServletRequest request,HttpServletResponse response)throwsAuthenticationException{//判断是否为Post请求if(!request.getMethod().equals("POST")){thrownewAuthenticationServiceException("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 =newHashMap<>();try{//将Json数据转换为Map
loginData =newObjectMapper().readValue(request.getInputStream(),Map.class);}catch(IOException e){thrownewRuntimeException(e);}String username = loginData.get(getUsernameParameter());String password = loginData.get(getPasswordParameter());if(username ==null){thrownewAuthenticationServiceException("用户名不能为空");}if(password ==null){thrownewAuthenticationServiceException("密码不能为空");}UsernamePasswordAuthenticationToken authRequest =UsernamePasswordAuthenticationToken.unauthenticated(username, password);setDetails(request, authRequest);returnthis.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 =newUsernamePasswordAuthenticationToken(username,password);this.setDetails(request,authRequest);returnthis.getAuthenticationManager().authenticate(authRequest);}}}
7、SpringSecurity核心配置:
packageorg.zhang.config;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.HttpStatus;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;importorg.springframework.security.config.http.SessionCreationPolicy;importorg.springframework.security.web.SecurityFilterChain;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.CorsConfigurationSource;importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importorg.zhang.service.impl.UserServiceImpl;importjava.util.Arrays;importstaticorg.springframework.security.config.Customizer.withDefaults;@Configuration@EnableWebSecuritypublicclassSecurityConfiguration{@AutowiredprivateUserServiceImpl userService;/**
* 获取AuthenticationManager(认证管理器),登录时认证使用
* @param AuthenticationConfiguration
* @return
* @throws Exception
*/@Bean(name ="authenticationManager")publicAuthenticationManagerauthenticationManager(AuthenticationConfiguration configuration)throwsException{return configuration.getAuthenticationManager();}@BeanpublicSecurityFilterChainfilterChain(HttpSecurity http)throwsException{
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(newMyLogoutSuccessHandler())).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(newObjectMapper().writeValueAsString(error));}).accessDeniedHandler((request, response, e)->{
response.setContentType("application/json;charset=UTF-8");ResultBody s =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0301);
response.getWriter().write(newObjectMapper().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();}//过滤静态资源@BeanpublicWebSecurityCustomizerwebSecurityCustomizer(){return(web)-> web.ignoring().antMatchers("/static/css");}// 注入登陆过滤器@BeanpublicLoginFilterloginFilter(AuthenticationManager authenticationManager)throwsException{LoginFilter loginFilter =newLoginFilter();
loginFilter.setFilterProcessesUrl("/root/doLogin");
loginFilter.setUsernameParameter("username");
loginFilter.setPasswordParameter("password");
loginFilter.setAuthenticationManager(authenticationManager);
loginFilter.setAuthenticationSuccessHandler(newSuccessHandler());
loginFilter.setAuthenticationFailureHandler(newFailHandler());return loginFilter;}//加入token验证过滤器@BeanpublicJWTAuthorizationFilterjwtAuthorizationFilter(AuthenticationManager authenticationManager){JWTAuthorizationFilter filter =newJWTAuthorizationFilter(authenticationManager);return filter;}//springsecurity跨域CorsConfigurationSourceconfigurationSource(){CorsConfiguration corsConfiguration =newCorsConfiguration();
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setMaxAge(3600L);UrlBasedCorsConfigurationSource source =newUrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);return source;}}
```# SpringSecurity使用总结:
## 1、Springsecurity目前问题:
>网上的教程大部分都是基于之前的版本,使用的是已经抛弃的继承WebSecurityConfigurerAdapter这个类进行SpringSecurity配置,但是新版本的SpringSecurity已经弃用了WebSecurityConfigurerAdapter这个类,以前的方法依旧可以使用,但是官方并不推荐使用这种方式
>>这点在官网也可以看到
https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
官方文档说的是:
To assist withthe transition tothisnew 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 SpringSecurity lambda DSL and the method `HttpSecurity#authorizeHttpRequests` todefine our authorization rules. If you are newtothe 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 tolearn more about why we choose touse `HttpSecurity#authorizeHttpRequests` you can check out the [reference documentation](https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html).
翻译过来就是
在 SpringSecurity5.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`,因为我们鼓励用户转向基于组件的安全配置为了帮助过渡到这种新的配置方式,我们编制了一份常见用例列表和建议的替代方案。
在下面的示例中,我们遵循最佳实践,使用 SpringSecurity 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、什么是SpringSecurity lambda DSL?
https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html
我依旧推荐大家去官网查看,看不懂可以用翻译。
在之前的版本中 我们更加常用的方式是覆盖重写configure(HttpSecurity http)方法,例如:
```java
@ConfigurationpublicclassWebSecurityConfigurerextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
http.authorizeHttpRequests().mvcMatchers("/index").permitAll().anyRequest().authenticated().and().formLogin();}}
而现版本推荐声明SecurityFilterChain而不是使用authorizeRequests,例如:
@BeanSecurityFilterChainweb(HttpSecurity http)throwsAuthenticationException{
http
.authorizeHttpRequests((authorize)-> authorize
.anyRequest().authenticated();)// ...return http.build();}
这里不多赘述原理 如果大家很感兴趣的话,我可以专门出一个专栏给大家讲解原理,从基础到新版本的区别
本文章更多在于配置
2、首先登陆成功配置
packageorg.zhang.config;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.http.HttpStatus;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.AuthenticationEntryPoint;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.xml.transform.Result;importjava.io.IOException;publicclassMyAuthenticationEntryPointimplementsAuthenticationEntryPoint{@Overridepublicvoidcommence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)throwsIOException,IOException{
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");ResultBody error =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);String s =newObjectMapper().writeValueAsString(error);
response.getWriter().println(s);}}
3、登陆失败配置
packageorg.zhang.config;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.security.authentication.AccountExpiredException;importorg.springframework.security.authentication.BadCredentialsException;importorg.springframework.security.authentication.CredentialsExpiredException;importorg.springframework.security.authentication.InternalAuthenticationServiceException;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.authentication.AuthenticationFailureHandler;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;publicclassFailHandlerimplementsAuthenticationFailureHandler{@OverridepublicvoidonAuthenticationFailure(HttpServletRequest request,HttpServletResponse response,AuthenticationException e)throwsIOException,ServletException{ResultBody result =null;if(e instanceofAccountExpiredException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0230);}elseif(e instanceofBadCredentialsException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0210);}elseif(e instanceofCredentialsExpiredException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0202);}elseif(e instanceofInternalAuthenticationServiceException){
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0201);}else{
result =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0220);}
response.setContentType("application/json;charset=UTF-8");String s =newObjectMapper().writeValueAsString(result);
response.getWriter().println(s);}}
这里面的ReusltBody是我自定义的统一返回数据类型,大家可以百度,也可以使用Map简单放回
4、注销成功配置
packageorg.zhang.config;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.security.core.Authentication;importorg.springframework.security.web.authentication.logout.LogoutSuccessHandler;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.HashMap;importjava.util.Map;//注销成功publicclassMyLogoutSuccessHandlerimplementsLogoutSuccessHandler{@OverridepublicvoidonLogoutSuccess(HttpServletRequest request,HttpServletResponse response,Authentication authentication)throwsIOException,ServletException{Map<String,Object> result =newHashMap<String,Object>();
result.put("msg","注销成功");
result.put("status",200);
response.setContentType("application/json;charset=UTF-8");String s =newObjectMapper().writeValueAsString(result);
response.getWriter().println(s);}}
5、认证入口点配置
packageorg.zhang.config;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.http.HttpStatus;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.AuthenticationEntryPoint;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.xml.transform.Result;importjava.io.IOException;publicclassMyAuthenticationEntryPointimplementsAuthenticationEntryPoint{@Overridepublicvoidcommence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)throwsIOException,IOException{
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");ResultBody error =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0111);String s =newObjectMapper().writeValueAsString(error);
response.getWriter().println(s);}}
6、JWT认证配置
packageorg.zhang.config;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.authority.SimpleGrantedAuthority;importorg.springframework.security.core.context.SecurityContextHolder;importorg.springframework.security.web.authentication.www.BasicAuthenticationFilter;importorg.springframework.util.ObjectUtils;importorg.zhang.utils.JwtUtils;importjavax.servlet.FilterChain;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.ArrayList;importjava.util.HashMap;publicclassJWTAuthorizationFilterextendsBasicAuthenticationFilter{publicJWTAuthorizationFilter(AuthenticationManager authenticationManager){super(authenticationManager);}@OverrideprotectedvoiddoFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain)throwsIOException,ServletException{//获取请求的TokenString 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获取用户信息privateUsernamePasswordAuthenticationTokengetAuthentication(String token){HashMap<String,Object> tokenInfo =JwtUtils.decode(token);if(ObjectUtils.isEmpty(tokenInfo)){returnnull;}String username =(String) tokenInfo.get("username");String[] roles =(String[]) tokenInfo.get("roles");ArrayList<SimpleGrantedAuthority> authorities =newArrayList<>();for(String role:roles){
authorities.add(newSimpleGrantedAuthority(role));}returnnewUsernamePasswordAuthenticationToken(username,null,authorities);}}
7、重写登陆配置(为了解决前端传值为Json类型)
packageorg.zhang.config;importcom.fasterxml.jackson.core.exc.StreamReadException;importcom.fasterxml.jackson.databind.DatabindException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.MediaType;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.authentication.AuthenticationServiceException;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.Authentication;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.zhang.pojo.User;importjavax.servlet.FilterChain;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.HashMap;importjava.util.Map;publicclassLoginFilterextendsUsernamePasswordAuthenticationFilter{//登陆认证接口@OverridepublicAuthenticationattemptAuthentication(HttpServletRequest request,HttpServletResponse response)throwsAuthenticationException{//判断是否为Post请求if(!request.getMethod().equals("POST")){thrownewAuthenticationServiceException("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 =newHashMap<>();try{//将Json数据转换为Map
loginData =newObjectMapper().readValue(request.getInputStream(),Map.class);}catch(IOException e){thrownewRuntimeException(e);}String username = loginData.get(getUsernameParameter());String password = loginData.get(getPasswordParameter());if(username ==null){thrownewAuthenticationServiceException("用户名不能为空");}if(password ==null){thrownewAuthenticationServiceException("密码不能为空");}UsernamePasswordAuthenticationToken authRequest =UsernamePasswordAuthenticationToken.unauthenticated(username, password);setDetails(request, authRequest);returnthis.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 =newUsernamePasswordAuthenticationToken(username,password);this.setDetails(request,authRequest);returnthis.getAuthenticationManager().authenticate(authRequest);}}}
7、SpringSecurity核心配置:
packageorg.zhang.config;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.HttpStatus;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;importorg.springframework.security.config.http.SessionCreationPolicy;importorg.springframework.security.web.SecurityFilterChain;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.CorsConfigurationSource;importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;importorg.zhang.comont.AliErrorCodeEnum;importorg.zhang.comont.ResultBody;importorg.zhang.service.impl.UserServiceImpl;importjava.util.Arrays;importstaticorg.springframework.security.config.Customizer.withDefaults;@Configuration@EnableWebSecuritypublicclassSecurityConfiguration{@AutowiredprivateUserServiceImpl userService;/**
* 获取AuthenticationManager(认证管理器),登录时认证使用
* @param AuthenticationConfiguration
* @return
* @throws Exception
*/@Bean(name ="authenticationManager")publicAuthenticationManagerauthenticationManager(AuthenticationConfiguration configuration)throwsException{return configuration.getAuthenticationManager();}@BeanpublicSecurityFilterChainfilterChain(HttpSecurity http)throwsException{
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(newMyLogoutSuccessHandler())).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(newObjectMapper().writeValueAsString(error));}).accessDeniedHandler((request, response, e)->{
response.setContentType("application/json;charset=UTF-8");ResultBody s =ResultBody.error(AliErrorCodeEnum.USER_ERROR_A0301);
response.getWriter().write(newObjectMapper().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();}//过滤静态资源@BeanpublicWebSecurityCustomizerwebSecurityCustomizer(){return(web)-> web.ignoring().antMatchers("/static/css");}// 注入登陆过滤器@BeanpublicLoginFilterloginFilter(AuthenticationManager authenticationManager)throwsException{LoginFilter loginFilter =newLoginFilter();
loginFilter.setFilterProcessesUrl("/root/doLogin");
loginFilter.setUsernameParameter("username");
loginFilter.setPasswordParameter("password");
loginFilter.setAuthenticationManager(authenticationManager);
loginFilter.setAuthenticationSuccessHandler(newSuccessHandler());
loginFilter.setAuthenticationFailureHandler(newFailHandler());return loginFilter;}//加入token验证过滤器@BeanpublicJWTAuthorizationFilterjwtAuthorizationFilter(AuthenticationManager authenticationManager){JWTAuthorizationFilter filter =newJWTAuthorizationFilter(authenticationManager);return filter;}//springsecurity跨域CorsConfigurationSourceconfigurationSource(){CorsConfiguration corsConfiguration =newCorsConfiguration();
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setMaxAge(3600L);UrlBasedCorsConfigurationSource source =newUrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);return source;}}
版权归原作者 秃头路上的小强 所有, 如有侵权,请联系我们删除。