SpringBoot整合SpringSecurit(一)实现ajax的登录、退出、权限校验

1、本文章中SpringBoot整合SpringSecurity,只是基于session方式,并且没有使用到redis。

2、登录、登出都是通过ajax的方式进行。

项目目录:

1、pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.9.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<groupId>com.example.springboot.security.demo</groupId>
	<artifactId>springboot-security-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot-security-demo</name>
	<description>springboot-security project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<!--spring-boot-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<!-- thymeleaf 模板引擎-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- spring security依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.0</version>
		</dependency>

		<!--谷歌处理json的工具包-->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.0</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
2、SecurityConfig 配置类
package com.example.springboot.security.demo.config.security;

import com.example.springboot.security.demo.handle.UserAuthenticationAccessDeniedHandler;
import com.example.springboot.security.demo.handle.UserLoginAuthenticationFailureHandler;
import com.example.springboot.security.demo.handle.UserLoginAuthenticationSuccessHandler;
import com.example.springboot.security.demo.handle.UserLogoutSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;

import javax.annotation.Resource;

/**
 * 配置 Security
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//开启security的权限校验注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 用户验证成功处理类
     */
    @Resource
    private UserLoginAuthenticationSuccessHandler userLoginAuthenticationSuccessHandler;

    /**
     * 用户验证失败处理类
     */
    @Resource
    private UserLoginAuthenticationFailureHandler userLoginAuthenticationFailureHandler;

    /**
     * 无权限操作时的处理类
     */
    @Resource
    private UserAuthenticationAccessDeniedHandler userAuthenticationAccessDeniedHandler;

    /**
     * 用户登出处理类
     */
    @Resource
    private UserLogoutSuccessHandler userLogoutSuccessHandler;



    //配置安全拦截机制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();//禁用CSRF控制,即spring security不再限制CSRF,即跨越访问

        http
                .authorizeRequests()
                .antMatchers("/static/**").permitAll()//不需要登录认证就可以访问,静态资源等不需要验证
                .antMatchers("/public/**").anonymous()//以public开头的接口,都可以匿名访问,即不用登录就可以访问
                .anyRequest().authenticated();//其他路径必须验证身份
        http
                .formLogin()
                .loginPage("/login-view.html")//登录页面,加载登录的html页面
                .loginProcessingUrl("/login")//发送Ajax请求的路径
                .usernameParameter("username")//请求验证参数
                .passwordParameter("password")//请求验证参数
                .successHandler(userLoginAuthenticationSuccessHandler)//验证成功处理
                .failureHandler(userLoginAuthenticationFailureHandler)//验证失败处理
                .permitAll();//登录页面无需设置验证

        http
                .logout()
                .logoutUrl("/logout")//登出路径
                .logoutSuccessHandler(userLogoutSuccessHandler)//登出处理
                .permitAll()//不需要身份认证
                .and()
                .exceptionHandling().accessDeniedHandler(userAuthenticationAccessDeniedHandler);//无权限时的处理
    }

    /**
     * 配置身份验证管理器
     * @param auth
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        //spring security 的登录实现
        daoAuthenticationProvider.setUserDetailsService(new UserDetailsServiceImpl());
        //使用BCrypt进行密码加密校验
        daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
        //设置hideUserNotFoundExceptions为false
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        return daoAuthenticationProvider;
    }
}
3、UserDetailsServiceImpl:spring security 的登录实现
package com.example.springboot.security.demo.config.security;

import com.example.springboot.security.demo.model.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * spring security 的登录实现
 */
@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    //这里通过注入,查询数据库实现登录
    /*@Resource
    private UserService userService;*/

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //登录账号
        System.out.println("username="+username);
        //1、这里是从数据库查询出来的对象
        User user = new User();
        user.setUsername(username);
        //这个加密密码是456
        user.setPassword("$2a$10$zgnAvX32nq.NaWtQ0SrMGOiJUH4jtTCXtLHWPPWBnHP4knzndbROm");

        //保存用户账号到session中,这样在controller中就可以直接获取
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        request.setAttribute("username",username);

        //模拟用户查询出来有问题
        if (username.equals("zhangsan")){
           throw new UsernameNotFoundException("用户不存在");
        }
        if (username.equals("zhangsan2")){
            throw new UsernameNotFoundException("用户被禁用");
        }

        //从数据库中查询用户的权限信息
        List<String> permissions = new ArrayList<>();
        permissions.add("sysUserInfo:view");
        permissions.add("sysUserInfo:update");
        permissions.add("sysUserInfo:delete");
        user.setPermissionList(permissions);

        //如果不重写UserDetails,那么可以用下面的这种写法
//        String[] permissionArray = new String[permissions.size()];
//        permissions.toArray(permissionArray);
//        UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(username).password("123").authorities(permissionArray).build();

        return user;
    }
}
4、无权限操作时的处理类
package com.example.springboot.security.demo.handle;

import com.example.springboot.security.demo.common.JsonData;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

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

/**
 * 无权限操作时的处理类
 */
@Slf4j
@Component("UserAuthenticationAccessDeniedHandler")
public class UserAuthenticationAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                       AccessDeniedException e) throws IOException, ServletException {
        log.info("{}","无权限处理");
        JsonData jsonData = new JsonData(500,"error");
        String json = new Gson().toJson(jsonData);
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();

        out.write(json);
        out.flush();
        out.close();
    }
}
5、用户验证失败处理类
package com.example.springboot.security.demo.handle;

import com.example.springboot.security.demo.common.JsonData;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

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

/**
 * 用户验证失败处理类
 */
@Slf4j
@Component("UserLoginAuthenticationFailureHandler")
public class UserLoginAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {



    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {

        String username = (String) request.getAttribute("username");
        System.out.println("登录用户:"+username);

        JsonData jsonData = null;

        /**
         * UserDetailsService 校验用户时,主动抛出的错误,如:用户信息不存在 用户被禁用等
         */
        if (exception instanceof UsernameNotFoundException){
            jsonData = new JsonData(402,exception.getMessage());
        }

        /**
         * 密码错误
         */
        if (exception instanceof BadCredentialsException){
            log.info(exception.getMessage());
            jsonData = new JsonData(403,"账号或密码错误");

            // String user_name = userService.findByUserNameAttemps(username);
            // if (user_name == null){
            //     String time = DateUtil.getTimeToString();
            //     UserLoginAttempts userLoginAttempts = new UserLoginAttempts(username,1,time);
            //     userService.saveAttempts(userLoginAttempts);
            // }


            // if(userService.getAttempts(username) == 1){
            //     String time = DateUtil.getTimeToString();
            //     userService.setAttempts(username,time);
            //     jsonData = new JsonData(403,"密码错误,你还有2次机会进行登录操作");
            // }
            // else if(userService.getAttempts(username) == 3){
            //     User user = userService.findByUserName(username);
            //     userService.LockUser(user.getId());
            //     jsonData = new JsonData(403,"最后一次尝试登陆失败,你已经被冻结了");
            // }
            // else if (userService.getAttempts(username) ==2 ){
            //     String time = DateUtil.getTimeToString();
            //     userService.setAttempts(username,time);
            //     jsonData = new JsonData(403,"密码错误,你还有1次机会进行登录操作");
            // }
        }

        String json = new Gson().toJson(jsonData);
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();

        out.write(json);
        out.flush();
        out.close();
    }
}
6、用户验证成功处理类
package com.example.springboot.security.demo.handle;

import com.example.springboot.security.demo.common.JsonData;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

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

/**
 * 用户验证成功处理类
 */
@Slf4j
@Component("UserLoginAuthenticationSuccessHandler")
public class UserLoginAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {


    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        JsonData jsonData = new JsonData(200,"认证OK");
        String json = new Gson().toJson(jsonData);
        log.info("{}","handle_success");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();

        out.write(json);
        out.flush();
        out.close();
    }
}
7、用户登出处理类
package com.example.springboot.security.demo.handle;

import com.example.springboot.security.demo.common.JsonData;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

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

/**
 * 用户登出处理类
 */
@Slf4j
@Component("UserLogoutSuccessHandler")
public class UserLogoutSuccessHandler implements LogoutSuccessHandler{

    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        JsonData jsonData = new JsonData(200,"退出成功");
        String json = new Gson().toJson(jsonData);
        log.info("{}","LogOut*******Success");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();

        out.write(json);
        out.flush();
        out.close();
    }
}

主要的是这几个配置,其他的配置可以通过源代码访问:

qw/springboot-security-demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值