SpringSecurity+SpringBoot前后端分离实现权限控制

Springboot + Spring Security 实现前后端分离登录认证及权限控制

一、环境准备

  • idea 2020.1

  • jdk 1.8

  • springBoot 2.26

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
                <version>2.2.6.RELEASE</version>
            </dependency>
            
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.6.RELEASE</version>
                        <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.60</version>
            </dependency>
    

二、创建Spring Security核心配置类:WebSecurityConfig。在这里配置权限控制,异常处理。

/**
 * @author tyeerth
 * @date 2020/5/1 - 15:39
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置认证方式等
        super.configure(auth);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //http相关的配置,包括登入登出、异常处理、会话管理等
        super.configure(http);
    }
}

三、创建用户登入认证类UserDetailsServiceImpl。

1、创建自定义异常类。

/**
 * 登录失败后抛出的异常
 * @author Lenovo
 *
 */
//public class LoginFailedException extends RuntimeException {
public class LoginFailedException extends RuntimeException {
	public LoginFailedException() {
	}

	public LoginFailedException(String message) {
		super(message);
	}

	public LoginFailedException(String message, Throwable cause) {
		super(message, cause);
	}

	public LoginFailedException(Throwable cause) {
		super(cause);
	}

	public LoginFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}
}

2、创建UserDetailsServiceImpl类,并实现UserDetailsService接口。

(1)重载父类的loadUserByUsername方法。

public class UserDetailsServiceImpl  implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return null;
    }
}

(2)用户登入逻辑

/**
 * @author tyeerth
 * @date 2020/5/1 - 15:50
 */
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private StudentService studentService;
    private static  final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
    /**
     总目标:根据表单提交的用户名查询User对象,并装配角色、权限等信息
     */
    @Override
    public UserDetails loadUserByUsername(
            // 表单提交的用户名
            String username
            ) throws UsernameNotFoundException {
        HttpSession session = ContextHolderUtils.getRequest().getSession();
        String password = ContextHolderUtils.getRequest().getParameter("password");
        Student studentByCardNumber = studentService.getStudentByCardNumber(username);
        session.setAttribute(LoginConsts.STUDENT,studentByCardNumber);

        if (username == null || "".equals(username)) {
            throw new LoginFailedException("用户名不能为空");
        }
        if (studentByCardNumber ==null){
            throw new LoginFailedException("当前用户不存在");
        }
        if (!MD5Utils.md5(password).equals(studentByCardNumber.getPassword())){
            throw new LoginFailedException("用户名和密码不匹配");
        }
        // 2.给Admin设置角色权限信息
        List<GrantedAuthority> authorities = new ArrayList<>();
        //添加用户权限
        authorities.add(new SimpleGrantedAuthority(studentByCardNumber.getRole()));
//        authorities.add(new SimpleGrantedAuthority("UPDATE"));
        logger.info("从session域中获取到的密码"+password);
        return new SecurityStudent(studentByCardNumber, authorities);
    }
}

四、密码的盐值加密方式。

1、定义md5的加密方式

@Component
public class PasswordEncoderService implements PasswordEncoder {
    /**
     * encode()方法对明文进行加密。
     * @param rawPassword
     * @return
     */
    @Override
    public String encode(CharSequence rawPassword) {
        return MD5Utils.md5(rawPassword.toString());
    }

    /**
     * matches()方法对明文加密后和密文进行比较
     * @param rawPassword
     * @param encodedPassword
     * @return
     */
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        String result = MD5Utils.md5(rawPassword.toString());
        return Objects.equals(result, encodedPassword);
    }
}

2、使用自定义的盐值加密方式

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

五、权限过滤配置

1、设置指定访问首页

@Override
protected void configure(HttpSecurity security) throws Exception {
//super.configure(security); 注释掉将取消父类方法中的默认规则
security.authorizeRequests() //对请求进行授权
.antMatchers("/index.jsp") //使用 ANT 风格设置要授权的 URL 地址
.permitAll() //允许上面使用 ANT 风格设置的全部请求
.anyRequest() //其他未设置的全部请求
.authenticated() //需要认证
}

2、在前后端分离中,未登入的情况返回对应的json数据。

结果示例:在这里插入图片描述

更新配置类

  .and()
                    .formLogin()
                    .successHandler(authenticationSuccessHandler)//登录成功处理逻辑
                    . failureHandler(authenticationFailureHandler)//登录失败处理逻辑
            .and()
                .exceptionHandling()					// 指定异常处理器
                .authenticationEntryPoint(authenticationEntryPoint)//匿名用户访问无权限资源时的异常处理
            .and()
                .logout()
                .permitAll()//允许所有用户
                .logoutSuccessHandler(logoutSuccessHandler)//登出成功处理逻辑
                .deleteCookies("JSESSIONID")//登出之后删除cookie// 开启退出功能

(1)匿名访问时返回的json数据

/**
 * 匿名访问时返回的json数据
 * @author tyeerth
 * @date 2020/5/2 - 13:26
 */
@Component
public class CustomizeAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msg","用户未登入");
        jsonObject.put("status","401");
        httpServletResponse.setContentType("text/json;charset=utf-8");
        httpServletResponse.getWriter().write(jsonObject.toJSONString());
    }
}

3、登入成功逻辑处理

(1)登入成功逻辑处理

/**
 * 登入成功逻辑处理
 * @author tyeerth
 * @date 2020/5/2 - 13:42
 */
@Component
public class CustomizeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {


        //返回json数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status",200);
        jsonObject.put("msg","登入成功");
        //处理编码方式,防止中文乱码的情况
        httpServletResponse.setContentType("text/json;charset=utf-8");
        //塞到HttpServletResponse中返回给前台
        httpServletResponse.getWriter().write(jsonObject.toJSONString());
    }
}
           

4、失败处理逻辑

/**
 * 登入失败的处理
 *
 * @author tyeerth
 * @date 2020/5/2 - 13:47
 */
@Component
public class CustomizeAuthenticationFailureHandler implements AuthenticationFailureHandler {


    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        //返回json数据
        JSONObject jsonObject = new JSONObject() ;
        if (e instanceof AccountExpiredException) {
            //账号过期
            jsonObject.put("msg","账号过期");
        } else if (e instanceof BadCredentialsException) {
            //密码错误
            jsonObject.put("msg","密码错误");
        } else if (e instanceof CredentialsExpiredException) {
            //密码过期
            jsonObject.put("msg","密码过期");
        } else if (e instanceof DisabledException) {
            //账号不可用
            jsonObject.put("msg","账号不可用");
        } else if (e instanceof LockedException) {
            //账号锁定
            jsonObject.put("msg","账号锁定");
        } else if (e instanceof InternalAuthenticationServiceException) {
            //用户不存在
            jsonObject.put("msg",e.getMessage());
            jsonObject.put("status","402");

        } else {
            //其他错误
            jsonObject.put("msg","其他错误");
        }
        //处理编码方式,防止中文乱码的情况
        httpServletResponse.setContentType("text/json;charset=utf-8");
        //塞到HttpServletResponse中返回给前台
        httpServletResponse.getWriter().write(jsonObject.toJSONString());
    }
}

5、退出登入逻辑

/**
 * 成功退出登入的逻辑
 * @author tyeerth
 * @date 2020/5/2 - 13:50
 */
@Component
public class CustomizeLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        JSONObject jsonObject =new JSONObject();
        jsonObject.put("msg","成功退出登入");
        httpServletResponse.setContentType("text/json;charset=utf-8");
        httpServletResponse.getWriter().write(jsonObject.toJSONString());
    }
}

六、会话管理(登录过时、限制单用户或多用户登录等)

1、限制用户登入

and().sessionManagement().
                    maximumSessions(1)//只能一个人登入

2、处理账号被挤下线处理逻辑

(1)会话管理逻辑

/**
 * 会话过期策略
 * @author tyeerth
 * @date 2020/5/2 - 14:29
 */
@Component
public class CustomizeSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msg","当前会话已过期,请重新登入");
        HttpServletResponse httpServletResponse = sessionInformationExpiredEvent.getResponse();
        httpServletResponse.setContentType("text/json;charset=utf-8");
        httpServletResponse.getWriter().write(jsonObject.toJSONString());
    }
}

(2)配置

.and().sessionManagement().//限制同一账号只能一个用户使用
                maximumSessions(1)
             .expiredSessionStrategy(sessionInformationExpiredStrategy)//会话信息过期策略会话信息过期策略(账号被挤下线)
### 回答1: vue springboot前后端分离开发实战pdf是一本介绍如何使用Vue和Spring Boot进行前后端分离开发的实战指南。本书详细讲解了如何使用Vue框架搭建前端应用,以及如何利用Spring Boot框架构建后端应用,旨在帮助读者掌握前后端分离开发的技术和方法。 在这本书中,作者首先介绍了前后端分离开发的概念和背景,解释了为什么前后端分离可以带来更好的开发体验和效率。接着,作者详细介绍了Vue框架的基本概念和使用方法,包括组件化开发、路由管理、状态管理等方面的内容。读者可以通过跟随书中的示例代码,逐步学习并实践Vue框架的应用。 在后半部分,作者重点介绍了Spring Boot框架的使用。读者将学习如何使用Spring Boot快速搭建后端应用,并了解如何通过RESTful API与前端应用进行数据交互。此外,作者还介绍了Spring SecuritySpring Data JPA等常用的配套技术,帮助读者构建安全可靠的后端应用。 本书不仅提供了理论知识,还提供了大量的实战案例和实例代码。读者可以跟随书中的示例项目逐步实践,从而更好地掌握Vue和Spring Boot的开发技巧。此外,本书还涉及了一些项目管理和部署的内容,帮助读者了解如何将前后端分离的应用部署到生产环境中。 总而言之,vue springboot前后端分离开发实战pdf是一本适合想要学习并实践前后端分离开发的开发人员的实用指南,通过学习本书,读者将获得丰富的知识和经验,能够独立设计和开发前后端分离的应用程序。 ### 回答2: 《Vue SpringBoot前后端分离开发实战PDF》这本书是一本关于前后端分离开发实践的指南。它结合了Vue和SpringBoot两个流行的开发框架,帮助开发者更好地理解和应用这两个技术。 在书中,作者首先介绍了前后端分离的概念和优势。前后端分离开发可以提高开发效率和协作性,同时也能提供更好的性能和扩展性。然后,作者详细介绍了Vue框架的基本知识和使用方法,包括Vue的搭建、组件的创建和组织等。读者可以通过实际的案例来学习和练习。 接着,作者转向SpringBoot框架的介绍和使用。SpringBoot是一个轻量级的Java开发框架,可以快速构建和部署应用程序。作者讲解了如何使用SpringBoot创建RESTful API,以及如何与Vue前端进行交互。 在书的后半部分,作者提供了一些实战案例和示例代码。这些案例涵盖了常见的前后端分离开发场景,如用户管理、权限控制、数据交互等。通过这些案例,读者可以了解到如何将Vue和SpringBoot无缝地结合起来,构建强大的应用程序。 总的来说,《Vue SpringBoot前后端分离开发实战PDF》是一本非常实用的书籍。它不仅系统地介绍了Vue和SpringBoot的基础知识和使用方法,还提供了丰富的实战经验和案例。对于想要掌握前后端分离开发技术的开发者来说,这本书是一个很好的学习资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值