天天看點

SpringSecurity前後端分離

pom檔案

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 實作對 Spring Security 的自動化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
           

前後端分離,後端不幹涉前端的跳轉,采用json格式傳遞資料

WebSecurityConfigurerAdapter 配置

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //退出
        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(myLogoutSuccessHandler);
        // 未登入&無權限傳回
        http.exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint);
        // 登入
        http.formLogin().loginProcessingUrl("/login")
                .successHandler(myAuthenticationSuccessHandler)
                .failureHandler(myAuthenticationFailureHandler)
                .and().authorizeRequests()
                .antMatchers("/","/login.html").permitAll()
                .anyRequest().authenticated()
                .and().csrf().disable();//關閉csrf防護
    }
}
           

AuthenticationSuccessHandler

  • 登入成功
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        Map<String, Object> map = new HashMap<>();
        map.put("status", 200);
        map.put("msg", authentication.getPrincipal());  // 登入成功的對象
        out.write(objectMapper.writeValueAsString(map));
        out.flush();
        out.close();
    }
}

           

AuthenticationFailureHandler

  • 登入失敗
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        Map<String, Object> map = new HashMap<>();
        map.put("status", 401);
        if (exception instanceof LockedException) {
            map.put("msg", "賬戶被鎖定,登入失敗!");
        } else if (exception instanceof BadCredentialsException) {
            map.put("msg", "使用者名或密碼輸入錯誤,登入失敗!");
        } else if (exception instanceof DisabledException) {
            map.put("msg", "賬戶被禁用,登入失敗!");
        } else if (exception instanceof AccountExpiredException) {
            map.put("msg", "賬戶過期,登入失敗!");
        } else if (exception instanceof CredentialsContainer) {
            map.put("msg", "密碼過期,登入失敗");
        } else {
            map.put("msg", "登入失敗!");
        }
        out.write(objectMapper.writeValueAsString(map));
        out.flush();
        out.close();
    }
}

           

LogoutSuccessHandler

  • 登出成功
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        Map<String, Object> map = new HashMap<>();
        map.put("status", 200);
        map.put("msg", "登出登入成功!");
        out.write(objectMapper.writeValueAsString(map));
        out.flush();
        out.close();
    }
}

           

AuthenticationEntryPoint

  • 認證失敗
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
//        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,authException.getMessage());
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        PrintWriter out = response.getWriter();
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code",403);
        map.put("message","未登入或無權限");
        out.write(objectMapper.writeValueAsString(map));
        out.flush();
        out.close();
    }

}

           

UserDetailsService

@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new User("user",passwordEncoder.encode("123"),new ArrayList<>());
    }
}

           

PasswordEncoder

@Component
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return encode(charSequence).equals(s);
    }

}