spring boot 整合 spring security

项目结构

添加依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>

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

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

修改配置文件

spring:
  freemarker:
    template-loader-path: classpath:/templates/
    charset: UTF-8
    cache: false
    suffix: .ftl

创建登录页

login.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页</title>
</head>
<body>
<form id="formLogin" method="post">
    用户名<input type="text" name="username" value="admin"/>
    密码<input type="text" name="password" value="123456"/>
    <input type="checkbox" name="remember-me" value="true"/>记住我
    <input type="button" onclick="login()" value="login"/>
</form>
</body>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script>
    function login() {
        $.ajax({
            type: "POST",//方法类型
            dataType: "json",//服务器预期返回类型
            url: "/login",   // 登录url
            data: $("#formLogin").serialize(),
            success: function (data) {
                console.log(data)
                if (data.code == 200) {
                    window.location.href = "/";
                } else {
                    alert(data.message);
                }
            }
        });
    }
</script>
</html>

创建首页

index.ftl

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
我是首页
</body>
</html>

创建SecurityConfiguration类

package com.lgg.config;

import com.lgg.service.MyAuthenticationService;
import com.lgg.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

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

/**
 * Security配置类
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Autowired
    private MyAuthenticationService myAuthenticationService;

    /**
     * http请求处理方法
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/toLoginPage", "/code/**").permitAll()//放行登录页面
                .anyRequest().authenticated()//所有请求都需要登录认证才能访问;
                .and().formLogin()//开启表单认证
                .loginPage("/toLoginPage")//自定义登录页面
                .loginProcessingUrl("/login")// 登录处理Url
                .usernameParameter("username").passwordParameter("password") //修改自定义表单name值.
                .successHandler(myAuthenticationService)//自定义登录成功处理
                .failureHandler(myAuthenticationService)//自定义登录失败处理
//                .defaultSuccessUrl("/")
//                .successForwardUrl("/")
                .and().logout().logoutUrl("/logout")//设置退出url
                .logoutSuccessHandler(myAuthenticationService)//自定义退出处理
                .and().rememberMe().rememberMeParameter("remember-me")// 自定义表单name值
                .tokenValiditySeconds(2 * 7 * 24 * 60 * 60)// 两周
                .tokenRepository(getPersistentTokenRepository())// 设置tokenRepository
                .and().csrf().disable(); // 关闭csrf防护

        // 允许iframe加载页面
        http.headers().frameOptions().sameOrigin();
    }

    @Autowired
    DataSource dataSource;

    /**
     * 持久化token,负责token与数据库之间的相关操作
     *
     * @return
     */
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);//设置数据源
        // 启动时创建一张表, 第一次启动的时候创建, 第二次启动的时候需要注释掉, 否则会报错
//        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }


    /**
     * WebSecurity
     *
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //解决静态资源被拦截的问题
        web.ignoring().antMatchers("/css/**", "/images/**", "/js/**", "/favicon.ico");
    }

    /**
     * 身份验证管理器
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);// 使用自定义用户认证
    }


}

创建MyAuthenticationService类

package com.lgg.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义登录成功或失败处理类
 */
@Service
public class MyAuthenticationService implements AuthenticationSuccessHandler, AuthenticationFailureHandler, LogoutSuccessHandler {

    @Autowired
    ObjectMapper objectMapper;
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        System.out.println("登录成功后续处理....");
//        redirectStrategy.sendRedirect(request, response, "/");
//
        Map result = new HashMap();
        result.put("code", HttpStatus.OK.value());// 设置响应码
        result.put("message", "登录成功");// 设置响应信息
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(result));
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        System.out.println("登录失败后续处理....");
        //redirectStrategy.sendRedirect(request, response, "/toLoginPage");
//        Map result = new HashMap();
//        result.put("code", HttpStatus.UNAUTHORIZED.value());// 设置响应码
//        result.put("message", exception.getMessage());// 设置错误信息
//        response.setContentType("application/json;charset=UTF-8");
//        response.getWriter().write(objectMapper.writeValueAsString(result));
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        System.out.println("退出成功后续处理....");
        redirectStrategy.sendRedirect(request, response, "/toLoginPage");
    }

}

创建MyUserDetailsService类

package com.lgg.service;


import com.lgg.entity.User;
import com.lgg.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.Service;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 基于数据库中完成认证
 */
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    UserService userService;

    /**
     * 根据username查询用户实体
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username);// 用户名没有找到
        }
        // 先声明一个权限集合, 因为构造方法里面不能传入null
        Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
        // 需要返回一个SpringSecurity的UserDetails对象
        UserDetails userDetails =
                new org.springframework.security.core.userdetails.User(user.getUsername(),
//                        "{noop}" + user.getPassword(),// {noop}表示不加密认证。
                        "{bcrypt}" + user.getPassword(),
                        true, // 用户是否启用 true 代表启用
                        true,// 用户是否过期 true 代表未过期
                        true,// 用户凭据是否过期 true 代表未过期
                        true,// 用户是否锁定 true 代表未锁定
                        authorities);
        return userDetails;
    }
}

创建HelloSecurityController类

package com.lgg.controller;


import com.lgg.entity.User;
import com.lgg.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * security入门案例
 */
@Controller
public class HelloSecurityController {


    @RequestMapping("/toLoginPage")
    public String toLoginPage() {
        return "login";
    }

    /**
     * 获取当前登录用户
     *
     * @return
     */
    @RequestMapping("/abc")
//    @ResponseBody
    public String getCurrentUser() {
        UserDetails userDetails = (UserDetails)
                SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        System.out.println("abc");
        return "abc";
    }

    /**
     * 获取当前登录用户
     *
     * @return
     */
    @RequestMapping("/loginUser1")
    @ResponseBody
    public UserDetails getCurrentUser1() {
        UserDetails userDetails = (UserDetails)
                SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return userDetails;
    }

    /**
     * 获取当前登录用户
     *
     * @return
     */
    @RequestMapping("/loginUser2")
    @ResponseBody
    public UserDetails getCurrentUser(Authentication authentication) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        return userDetails;
    }

    /**
     * 获取当前登录用户
     *
     * @return
     */
    @RequestMapping("/loginUser3")
    @ResponseBody
    public UserDetails getCurrentUser(@AuthenticationPrincipal UserDetails userDetails) {
        return userDetails;
    }

    @Autowired
    private UserService userService;

    /**
     * 根据用户ID查询用户
     *
     * @return
     */
    @GetMapping("/{id}")
    @ResponseBody
    public User getById(@PathVariable Integer id) {
        //获取认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // 判断认证信息是否来源于RememberMe
        if (RememberMeAuthenticationToken.class.isAssignableFrom(authentication.getClass())) {
            throw new RememberMeAuthenticationException("认证信息来源于RememberMe,请重新登录");
        }
        User user = userService.getById(id);
        return user;
    }


}

启动项目验证

访问任意接口,都会被路由到登录页面login.ftl,只有登录成功后,才能正常访问其他接口。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/196559.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode刷题详解十

188. 买卖股票的最佳时机 IV&#xff08;最多买卖k次&#xff09; 注意事项 这道题和最多买卖两次是一模一样的思路就是把2换成k了但是还是有几个地方需要注意的 给的整数数组可能为0k其实没有很大&#xff0c;可以想一下&#xff0c;最多为n/2(n是数组的长度) int maxProfit…

大型网站系统架构演化(Web)

大型网站系统架构演化 大型网站系统架构演化需要关注的维度涉及的技术演进过程单体架构垂直架构使用缓存改善网站性能缓存与数据库的数据一致性问题缓存技术对比Redis分布式存储方案Redis集群切片的常见方式Redis数据类型Redis 淘汰算法 大型网站系统架构演化 需要关注的维度 …

2024年最受欢迎的项目管理工具盘点

十大项目管理系统包括&#xff1a;1.产品研发项目管理工具&#xff1a;PingCode&#xff1b;2.通用项目协作工具&#xff1a;Worktile&#xff1b;3.开源项目管理系统&#xff1a;Redmine&#xff1b;4.IT/敏捷项目管理系统&#xff1a;Jira&#xff1b;5.免费个人项目管理&…

NX二次开发UF_CURVE_create_arc_point_point_radius 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_create_arc_point_point_radius Defined in: uf_curve.h int UF_CURVE_create_arc_point_point_radius(tag_t point1, tag_t point2, double radius, UF_CURVE_limit_p_t l…

问答社区运营的核心是什么?

问答社区是用户在平台上获得信息的一种方式&#xff0c;一般问答社区适用于医疗行业&#xff0c;法律行业等专业领域的行业&#xff0c;可以划分为知识型分享社区的一种&#xff0c;用户提供提问&#xff0c;邀请回答&#xff0c;选择最佳回复&#xff0c;设置问题围观&#xf…

字符串逆序问题

写一个函数&#xff0c;可以将任意输入的字符串逆序&#xff08;要可以满足多组输入&#xff09; 这个题有三个点 1.要读入键盘输入的字符串&#xff0c;所以要用到字符串输入函数 2.可以进行多组输入 3.把输入的n组字符串都逆序 #define _CRT_SECURE_NO_WARNINGS 1 #incl…

Portraiture2024最新Photoshop磨皮插件更新啦

Portraiture是一款由Imagenomic公司研发的Photoshop磨皮插件。该插件以其优秀的磨皮效果&#xff0c;成为了众多摄影师和化妆师使用的首选插件。Portraiture主要用于影楼、婚纱、时尚摄影等各个领域。其主要特点是能够轻松地模拟人眼的视觉感受&#xff0c;自然地修饰人像照片。…

【Linux专题】http(s)代理

【赠送】IT技术视频教程&#xff0c;白拿不谢&#xff01;思科、华为、红帽、数据库、云计算等等_厦门微思网络的博客-CSDN博客文章浏览阅读444次。风和日丽&#xff0c;小微给你送福利~如果你是小微的老粉&#xff0c;这里有一份粉丝福利待领取...如果你是新粉关注到了小微&am…

元宇宙的八个关键技术介绍!

人工智能&#xff08;AI&#xff09;、物联网、增强现实、虚拟现实、区块链、NFT、3D建模、空间和边缘计算等技术使最元宇宙开发成为可能。本文对元宇宙的8个关键技术进行了介绍。 人工智能 人工智能技术中的目标分割、目标追踪、姿态估计等是元宇宙场景中感知现实的关键工具&…

【笔记】小白学习电路维修

学习视频&#xff08;b站&#xff09;&#xff1a;从0开始学电路 从0开始学电路维修 p1 黄色长方体元件P2 故障率最高的元件p3带芯铜丝线圈是什么区分电感和变压器接入电路分析&#xff1a; p4 交流和直流分界线整流桥接线整流桥故障判断 带色环的不一定是电阻 p1 黄色长方体元…

51单片机项目(16)——基于51单片机的水箱冷却系统

1.项目背景 汽车水箱又称散热器&#xff0c;是汽车冷却系统中主要机件&#xff1b;其功用是散发热量&#xff0c;冷却水在水套中吸收热量&#xff0c;流到散热器后将热量散去&#xff0c;再回到水套内而循环不断。从而达到散热调温的效果。它还是汽车发动机的重要组成部分。 汽…

解决ssh使用public key远程登录服务器拒绝问题

目录 使用场景windows安装ssh客户端使用powershell ssh登录服务器生成密钥文件ubuntu ssh服务器配置使用vscode远程登录使用Xshell远程登录使用MobaXtem远程登录Server refused our key问题解决方案 使用场景 使用vscode远程ssh登录使用public key不需要输入密码,比较方便. w…

Java 之 lambda 表达式(一)

目录 一. 前言 二. lambda 表达式语法 2.1. 语法1&#xff1a;无参&#xff0c;无返回值 2.2. 语法2&#xff1a;一个参数&#xff0c;无返回值 2.3. 语法3&#xff1a;两个参数&#xff0c;lambda 体中有多条语句 2.4. 语法4&#xff1a;两个以上参数&#xff0c;有返回…

Java 常用容器

目录 列表栈&#xff08;类&#xff09;队列(接口)setMap 列表 package com.czl;import java.util.ArrayList; import java.util.List; //AltEnter导入包 public class Main {public static void main(String[] args) throws Exception{List<Integer> list new ArrayLis…

群晖NAS配置之自有服务器ngrok实现内网穿透

群晖NAS配置之自有服务器ngrok实现内网穿透 前言-内网穿透 内网穿透是指通过一种技术让外部网络可以访问到内网的NAS设备&#xff0c;这样即使在不同网络环境下&#xff0c;也能够远程访问和管理NAS设备。以下是一些常见的内网穿透方案&#xff1a; Synology官方提供的Quick…

【Java Spring】SpringBoot常用插件

文章目录 1、Lombok1.1 IDEA社区版安装Lombok1.2 IDEA专业版安装Lombok1.3 Lombok的基本使用 2、EditStarters2.1 IDEA安装EditStarters2.2 EditStarters基本使用方法 1、Lombok 是简化Java开发的一个必要工具&#xff0c;lombok的原理是编译过程中将lombok的注解给去掉并翻译…

二百零八、Hive——HiveSQL异常:Select查询数据正常,但SQL语句加上group by查询数据为空

一、目的 在HiveSQL的DWD层中&#xff0c;需要对原始数据进行去重在内的清洗&#xff0c;结果一开始其他数据类型的清洗工作都正常&#xff0c;直到碰到转向比数据。 一般的SQL查询有数据&#xff0c;但是加上group by以后就没数据&#xff1b; 一般的SQL查询有数据&#xf…

很清楚展示GPT插件的调用过程,人工智能(AI)的潜在危险与好处 超级智能 未来

好处&#xff0c;未来 很清楚展示GPT插件的调用过程&#xff1a; 把请求和要求发chatGPT chatGPT返回markdown格式发给插件 插件返回结果给用户。 你不用别人用。 人工智能&#xff08;AI&#xff09;的最危险之处通常与以下几个方面有关&#xff1a; 自主决策能力过强&…

轻量级项目群管理

敏捷开发流程管理&#xff1a; Leangoo领歌是一款永久免费的专业的敏捷开发管理工具&#xff0c;提供端到端敏捷研发管理解决方案&#xff0c;涵盖敏捷需求管理、任务协同、进展跟踪、统计度量等。 Leangoo支持敏捷研发管理全流程&#xff0c;包括小型团队敏捷开发&#xff0c;…

创建SpringBoot Helloword 程序详细步骤

本文档实现SpringBoot hello word 程序&#xff0c;翻译于Spring | Quickstart 目录 一、项目创建步骤1.1 创建项目1.2 添加代码1.3 运行 参考教程 一、项目创建步骤 1.1 创建项目 在官网Spring Initializr上创建项目 1.2 添加代码 在IDE中打开项目并在src/main/java/com/zo…