security 登陆成功 访问 403_spring security自定义处理登陆

spring security

自定义处理登陆

pom

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.68</version>
 </dependency>

项目结构

3b2fbef625f95f54e73c73f92836e41a.png

配置类

 /**
  * @author spp
  * @date 2020-06-11 14:17
  **/
 @EnableWebSecurity
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
     final
     AuthUserDetailsServiceImpl userDetails;
     final
     AuthSuccessHandler authSuccessHandler;
     final
     AuthFailHandler authFailHandler;
 ​
     public SecurityConfig(AuthSuccessHandler authSuccessHandler, AuthFailHandler authFailHandler, AuthUserDetailsServiceImpl userDetails) {
         this.authSuccessHandler = authSuccessHandler;
         this.authFailHandler = authFailHandler;
         this.userDetails = userDetails;
     }
 ​
     @Override
     public void configure(WebSecurity web) throws Exception {
         //忽略请求,不经过security过滤器链
         web.ignoring().mvcMatchers(HttpMethod.GET,"/**");
     }
 ​
     /**
      * 从容器中取出 AuthenticationManagerBuilder,执行方法里面的逻辑之后,放回容器
      * @param authenticationManagerBuilder x
      * @throws Exception
      */
     @Autowired
     public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
         authenticationManagerBuilder.userDetailsService(userDetails).passwordEncoder(new BCryptPasswordEncoder());
     }
 ​
     @Override
     public void configure(HttpSecurity http) throws Exception {
         //解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request(cors 预检请求)
         http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();
         //让Security永远不会创建HttpSession,它不会使用HttpSession来获取SecurityContext
         http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                 .and().headers().cacheControl();
 ​
         http.authorizeRequests()
                 .antMatchers("/admin/**")
                 .hasAuthority("root")
                 .antMatchers("/").permitAll();
 ​
         //登陆
         http.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
         //处理异常情况:认证失败和权限不足
         http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
             response.getWriter().println("认证失败");
         }).accessDeniedHandler((request, response, accessDeniedException) -> {
             response.getWriter().println("你的权限不足以访问该资源");
         });
     }
 ​
     /**
      * 登陆拦截器
      * @return
      * @throws Exception
      */
     @Bean
     public UsernamePassAuthFilter myUsernamePasswordAuthenticationFilter() throws Exception {
         UsernamePassAuthFilter filter = new UsernamePassAuthFilter();
         //成功后处理
         filter.setAuthenticationSuccessHandler(authSuccessHandler);
         //失败后处理
         filter.setAuthenticationFailureHandler(authFailHandler);
         filter.setAuthenticationManager(authenticationManagerBean());
         return filter;
     }
 ​
 }

自定义的登陆过滤器,继承UsernamePasswordAuthenticationFilter

 /**
  * @author spp
  * @date 2020-06-09 15:34
  * 自定义登陆
  **/
 ​
 public class UsernamePassAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
 ​
     @Autowired
     UserService service;
     public static final String APPLICATION_JSON = "application/json";
     public static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8";
     @Override
     public Authentication attemptAuthentication(HttpServletRequest request,
                                                 HttpServletResponse response) throws AuthenticationException {
         String contentType = request.getContentType();
 ​
         if (contentType == null){
             throw new AuthException("内容类型不符");
         }
         if ( APPLICATION_JSON.equals(contentType) || APPLICATION_JSON_UTF8.equals(contentType)) {
             UsernamePasswordAuthenticationToken authRequest;
             User user;
             try (InputStream is = request.getInputStream()) {
                 int len;
                 byte[] b = new byte[2048];
                 StringBuilder sb = new StringBuilder();
                 while ((len = is.read(b)) != -1){
                     sb.append(new String(b,0,len));
                 }
                 user = JSON.parseObject(sb.toString(),User.class);
             } catch (IOException e) {
                 //将异常放到自定义的异常类中
                 throw new AuthException(e.getMessage());
             }catch (JSONException j){
                 throw new AuthException("参数映射错误"+j.getMessage());
             }
             try {
                 if (user != null) {
                     //获得账号、密码
                     logger.info(user);
                     //登陆逻辑
                     if ("admin".equals(user.getUsername()) && "123456".equals(user.getPassword())){
                         authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());
                         setDetails(request, authRequest);
                         return getAuthenticationManager().authenticate(authRequest);
                     }else {
                         throw new AuthException("用户名密码不匹配");
                     }
                 }
             } catch (Exception e) {
                 throw new AuthException(e.getMessage());
             }
             return null;
         } else {
             response.setStatus(405);
             throw new AuthException("内容类型不符");
         }
     }
 }

自定义登陆成功处理类,实现AuthenticationSuccessHandler接口

 /**
  * @author spp
  * @date 2020-06-11 14:28
  **/
 @Slf4j
 @Component
 public class AuthSuccessHandler implements AuthenticationSuccessHandler {
     @Override
     public void onAuthenticationSuccess(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Authentication authentication) throws IOException {
         //取得账号信息
         UserDetails userDetails = (UserDetails) authentication.getPrincipal();
         log.info(userDetails + "--->>登陆成功");
         response.getWriter().println("success");
     }
 }
 ​

自定义登陆失败处理类,实现AuthenticationFailureHandler接口

 /**
  * @author spp
  * @date 2020-06-09 16:50
  **/
 @Component
 @Slf4j
 public class AuthFailHandler implements AuthenticationFailureHandler {
     @Override
     public void onAuthenticationFailure(HttpServletRequest request,
                                         HttpServletResponse response,
                                         AuthenticationException e) throws IOException {
         log.info("登陆失败--->>>>");
         //输出
         JSONUtil.WriteJSON(request, response,"登陆失败:"+e.getMessage());
     }
 }

登陆成功后给其添加权限或者身份

实体类需要实现UserDetails接口

 /**
  * @author spp
  * @date 2020-06-09 15:54
  **/
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class AuthUser implements UserDetails {
     private String username;
 ​
     private String password;
 ​
     private Integer state;
 ​
     public AuthUser(String username, String password, Integer state, Collection<? extends GrantedAuthority> authorities) {
         this.username = username;
         this.password = password;
         this.state = state;
         this.authorities = authorities;
     }
 ​
     private Boolean rememberMe;
 ​
     private Collection<? extends GrantedAuthority> authorities;
 ​
     //账号是否未过期
     @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接口

 /**
  * @author spp
  * @date 2020-06-11 14:34
  * 登陆成功后添加权限或者身份
  **/
 @Component
 public class AuthUserDetailsServiceImpl implements UserDetailsService {
 ​
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
         return new AuthUser(username,new BCryptPasswordEncoder().encode("123456"),null);
     }
 }

测试

2c1f17b3df146b1946a41fe6da1c7cd3.png

ac0ad398cb03351b1c22188aeed428e3.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值