SpringSecurity 入门

SpringSecurity 入门

一步一步来。

集各家之所长,师从 尚硅谷、狂神、三更草堂;如果文中发现跟他们有类似的,不用想,就是他们那里拿来的

事先声明,本人很菜,其中有说的误人子弟的,请大家指出来。

环境:

idea2020.1 SpringBoot2.6.3 MyBatisPlus Maven3.6.3 SpringSecurity Lombok MySQL8.0.23…

总述:

先根据三家总的说一下,大致可以划分为两类: **1.**前后端不分离 **2.**前后端分离

SpringSecurity概述

这一部分就是简述它的。

它是一款重量级安全框架,说起安全框架就立马想起两个关键词“认证”和“授权”。

一般来说,Web 应用的安全性包括**用户认证(Authentication)和用户授权(Authorization)**两个部分,这两点也是 Spring Security 重要核心功能。 英语单词务必给我记住

(1)用户认证指的是:就是系统认为用户是否能登录,账号密码匹配的问题

(2)用户授权指的是:就是系统判断用户是否有权限去做某些事情,比如vip权限可以干啥,普通用户却不行

例子:老婆与卧室

老婆在卧室里面睡觉,

情况一:这时响起了敲门声,通过猫眼看是你(老公),认证通过,授权老公身份,允许进入卧室,嘿嘿嘿;

情况二:通过猫眼看是隔壁老王(熟人),认证通过,没有权限跟老婆一起进卧室,老王黯然神伤;

情况三:陌生人,客厅门都进不来

同台竞争对手:Shiro(大致学过,估计忘记了,轻量级)

技术选型推荐:SSM + Shiro SpringBoot + SpringSecurity

-前后端不分离

下面代码块中标记有项目代码的,就可作为练手的,即写进项目自行测试的(记号为 @@txf)

–入门案例

新建一个SpringBoot项目

目录结构如图:在这里插入图片描述

在这里插入图片描述

需要引入的依赖:@@txf

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

    <!--先把这个注释掉-->
<!--        <dependency>--> 
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-security</artifactId>-->
<!--        </dependency>-->

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

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

HelloController.java @@txf

@Controller
public class HelloController {

    @RequestMapping("/hello")
    public String HelloPage() {
        return "hello";
    }
}

hello.html @@txf(templates下面)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>hello</title>
</head>
<body>
    这是hello界面
</body>
</html>

启动项目,浏览器运行 localhost:8080/hello

会直接跳转到templates下面的hello.html界面

然后将pom.xml里面的security依赖加上,刷新maven,重新运行项目,浏览器输入 localhost:8080/hello

出现如下界面:
在这里插入图片描述

我们发现地址栏自动发生了变化,界面也不是hello了,在控制台我们甚至可以看到这么一出
在这里插入图片描述

这就说明,SpringSecurity拦截到了我们的/hello请求,发现没有进行认证(登录),就给我们默认处理,跳转到了这个界面(默认的)。

此时,username输入user, password复制控制到输出的密码,就可以进行登录了。以上是Security默认生成了密码,为第一种方式;第二种方式:在配置文件中自己配置username和password。如下

application.properties或者application.yml @@txf

server.port=8080 #这是我自己配置的端口号,爱写不写,还是养成写的好习惯

#在配置文件中配置账号密码
spring.security.user.name=txf
spring.security.user.password=123456

配置完重新启动项目,发现控制台不会自动生成密码了,此时localhost:8080/hello跳转去/login时用我们在配置文件中的账号密码登录即可。登录完成就可以看到hello了。

你如果账号密码输入的不正确,肯定是通过不了的,自己动手实践去。

如果这样写账号密码的话,是固定的,实际场景肯定是从数据库中查到的!!!!!!!!

–加入数据库

引入依赖 @@txf

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>

创建数据库test,创建表customer: @@txf(数据库建表)

DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `realName` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '真实姓名',
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '账号',
  `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
  `age` int NULL DEFAULT 20 COMMENT '年龄',
  `adress` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '家庭住址',
  `gender` int NULL DEFAULT 1 COMMENT '性别',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of customer
-- ----------------------------
INSERT INTO `customer` VALUES (1, '田小锋', 'txfnbnbnb', '123456', 20, '湖北省荆门市京山市', 1);

里面加入了一条数据,那就是我了。。。

配置文件中肯定是要修改的,加入下面这些 @@txf

#数据库
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=GMT%2B8&useUnicode=true&allowMultiQueries=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis-plus.type-aliases-package=com.feng.securitydemo01.pojo
mybatis-plus.mapper-locations=classpath:/mapper/*.xml

实体类pojo包 @@txf

package com.feng.securitydemo01.pojo;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("customer")
public class Customer {

    @TableId
    private Integer id;

    private String realname;
    private String username;
    private String password;
    private Integer age;
    private String adress;
    private Integer gender;
}

Mapper接口 @@txf

package com.feng.securitydemo01.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.feng.securitydemo01.pojo.Customer;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface CustomerMapper extends BaseMapper<Customer> {
}

–原理初探

页面提交方式必须为 post 请求

先放一张别人的图,SpringSecurity本质是一个过滤器链。

大致流程:

在这里插入图片描述

各个过滤器及其顺序:

在这里插入图片描述

上图只需要明白流程,不要记!大致是从顶部先一步一步调用走到底部,然后从底部返回值一步一步回到顶部

我们在它默认的登录页面输入的username和password,经过上图一系列过程,最终到UserDetailsService中。这个UserDetailsService是一个接口。

package com.feng.securitydemo01.service.Impl;

@Service //这个就不用多说了吧,交给Spring容器来管理,替换掉默认的
public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //在这个方法里面,根据前端页面传过来的username,我们去数据库做一系列查询操作,
        //返回值是一个UserDetails,
    }
}

//==================下面是具体实现=====================       @@txf
package com.feng.securitydemo01.service.Impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.feng.securitydemo01.mapper.CustomerMapper;
import com.feng.securitydemo01.pojo.Customer;
import com.feng.securitydemo01.pojo.LoginCustomer;
import org.springframework.beans.factory.annotation.Autowired;
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.Objects;

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private CustomerMapper customerMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<Customer> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        Customer customer = customerMapper.selectOne(wrapper);

        if (Objects.isNull(customer) ) { //空的,说明查不到
            throw new UsernameNotFoundException("用户名不存在!");
        }

        //查到了,注意,这里现在我们不需要密码校验,直接封装为UserDetails返回就行了
        //UserDetail我们自己实现
        return new LoginCustomer(customer);

    }
}

UserDetails

//点进源码发现这也是一个接口,是接口我们就可以去实现它,来完成自定义(虽然它已经有实现类了)
public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}
//===============================源码===========================================
//LoginCustomer.java   自定义实现UserDetails接口
//=====================具体实现===========       @@txf
package com.feng.securitydemo01.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

@Data
@AllArgsConstructor
public class LoginCustomer implements UserDetails {
    private Customer customer; //存入我们根据username查到的customer

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() { //获取权限,先不看
        return null;
    }
    @Override
    public String getPassword() {
        return customer.getPassword();
    }
    @Override
    public String getUsername() {
        return customer.getUsername();
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {  //能使用
        return true;
    }
}

–流程分析

根据上面的流程图文字解析:

  1. 根据传过来的username和password构造UsernamePasswordAuthenticationToken;(UsernamePasswordAuthenticationToken继承自AbstractAuthenticationToken,抽象类AbstractAuthenticationToken实现Authentication接口。)

  2. 调用方法ProviderManager.authenticate(参数类型是Authentication) ,所以可以传进去上面构造的User…Token。

 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        ..........................
        Iterator var9 = this.getProviders().iterator();

        while(var9.hasNext()) {
          .......
          //这里就是AbstractUserDetailsAuthenticationProvider的authenticate,
         result = provider.authenticate(authentication);
            
           .......
        }
     
     
     
抽象类AbstractUserDetailsAuthenticationProvider的authenticate,
user = this.retrieveUser(username, (UsernamePasswordAuthenticationToken)authentication);
  1. AbstractUserDetailsAuthenticationProvider的子类DaoAuthenticationProvider.retrieveUser()
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        .................
            //这里用上了我们的UserDetailsService!!!!!!!!!!!
            //是不是就返回了UserDetails!!!
            UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
          ...................
    }


//看看这个方法是干什么的???????????
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            this.logger.debug("Failed to authenticate since no credentials provided");
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        } else {
            String presentedPassword = authentication.getCredentials().toString();
            
            //=========================
            // this.passwordEncoder 密码校验,知道为什么不用你自己写了吧。自定义也行
            //============================
            if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
                this.logger.debug("Failed to authenticate since password does not match stored value");
                throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
            }
        }
    }

在这里插入图片描述

–加密

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id “null”

还有一种是什么not like 什么什么的,

//密码加密
//假如数据库泄露了,密码如果是明文存储,那还搞个鬼子!!!!!!!!!所以,安全框架嘛,必然考虑得如此周到
/*
我们存进数据库里面的密码,那就肯定是要加密的了,即存进去的是密文                   @@txf
*/
package com.feng.securitydemo01.config;        

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

在这里插入图片描述

//加密测试
@Test
    public void test() {
        String s = "123456";
        String s1 = encoder.encode(s);
        String s2 = encoder.encode(s);
        System.out.println(s1 +" " + s2);
    }
//输出结果,居然不一样!!!!这我们就不深究了。。。。反正都是123456
$2a$10$ipQhvDpdCZrpAc.JR7og/.l.3EpPovD2NlMcpUnYH4xv8inMemhI6 $2a$10$LDPVG9vvJvjBHsVfgLv0RO.2sq5LIscT01WBaybTf7bpQ.XHFOASa
    
//密码匹配测试
    @Test
    public void test() {
        String s = "123456";
        boolean matches = encoder
            .matches(s,"$2a$10$ipQhvDpdCZrpAc.JR7og/.l.3EpPovD2NlMcpUnYH4xv8inMemhI6");
        System.out.println(matches);  //true
    }

所以数据库中的123456要改咯,改成密文。将配置文件中自定义的username和password注掉,再来启动项目测试。这时候输入的就是数据库中的了。

数据中:

1	田小锋	txf	$2a$10$ipQhvDpdCZrpAc.JR7og/.l.3EpPovD2NlMcpUnYH4xv8inMemhI6	20	湖北省荆门市京山市	1

启动项目:localhost:8080/hello 这时候输入自己的账号密码即可。

仔细看上面两个流程图,流程一定得明白,源码才勉强看得懂

–小项目

在上面的基础之上,改造页面,权限访问那些

授权基本流程

​ 在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。

​ 所以我们在项目中只需要把当前登录用户的权限信息也存入Authentication。

​ 然后设置我们的资源所需要的权限即可

数据添加:(后面两个的密码是txf123)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

用户拥有某一种角色,角色对应有哪些权限。上面这些表的意思。(走后门、查找、浏览)三种权限,admin所有权限都有,vip只有两种,user只有一种。四张表的名字分别是customer,cusrole,cusauth,cusroleauth。

有了权限,我们需要从数据库里面根据customer的id查询该用户所拥有的权限名称。

SELECT authname 
FROM cusauth
WHERE authid in (
	SELECT authid 
	FROM cusroleauth
	WHERE roleid = (SELECT roleid 
				FROM customer
				WHERE id = 1)
)

#这里可不可以请大佬帮我换一种方式查出来。。。本人着实有点愚钝

Mapper接口里面 @@txf

@Mapper
@Repository
public interface CustomerMapper extends BaseMapper<Customer> {
    List<String> getAuthorizaById(Integer id);
}

Mapper.xml ( resourses下的mapper目录里面CustomerMapper.xml) @@txf

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.feng.securitydemo01.mapper.CustomerMapper">
    <select id="getAuthorizaById" resultType="string" parameterType="int">
        SELECT authname
        FROM cusauth
        WHERE authid in (
            SELECT authid
            FROM cusroleauth
            WHERE roleid = (SELECT roleid
                        FROM customer
                        WHERE id = #{id})
        )
    </select>

</mapper>

修改

MyUserDetailsService和loginCustomer @@txf

//DetailsService
//查询权限封装进去
List<String> authoriza = customerMapper.getAuthorizaById(customer.getId());
//查到了,注意,这里现在我们不需要密码校验,直接封装为UserDetails返回就行了
//UserDetail我们自己实现
return new LoginCustomer(customer,authoriza);


//LoginUserDetailsService.java    
private Customer customer;
private List<String> myAuthorities;
//存储SpringSecurity所需要的权限信息的集合
private List<GrantedAuthority> authorities;

public LoginCustomer(Customer customer, List<String> myAuthorities) {
        this.customer = customer;
        this.myAuthorities = myAuthorities;
    }

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    if(authorities!=null){
        return authorities;
    }
    //myAuthorities
    authorities = myAuthorities.stream().
        map(SimpleGrantedAuthority::new)
        .collect(Collectors.toList());
    return authorities;
}

@EnableGlobalMethodSecurity(prePostEnabled = true)     
//主启动类上添加此注解,先开启相关配置。

HelloController @@txf

package com.feng.securitydemo01.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {

    @RequestMapping({"/","/index"})
    public String index() {
        return "index";
        
    }
    @RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }
    @GetMapping("/noauth")
    public String accessDenyPage(){
        return "noauth"; }

    @RequestMapping("/houmen")
    @PreAuthorize("hasAuthority('zouhoumen')") //看登录的用户是否有此权限。
    public String houmen() {
        return "admin/houmen";
    }

    @RequestMapping("/find")
    @PreAuthorize("hasAuthority('find')")
    public String find() {
        return "vip/find";
    }

    @RequestMapping("/hello")
    @PreAuthorize("hasAuthority('look')")
    public String HelloPage() {
        return "hello";
    }
}

此外,我们希望对首页,不需要登录就能访问怎么做呢? @@txf

@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //================这中间配置即可
   @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()  //关闭csrf
                .formLogin()
//                .usernameParameter("自己根据情况写") 自定义表单的username,password
//                .passwordParameter("自己情况写")
            //还有rememberme、logout功能,极其简单,这里就不说了
                .loginProcessingUrl("/login")  //登录的url
                .successForwardUrl("/index")   //登录成功后走/index
                .and()
                .authorizeRequests().antMatchers("/","/index","/toLogin").permitAll()  //"/","/index"放行
                .anyRequest().authenticated(); //所有请求都需要认证
        
        //配置403处理器,修改response中的内容,
        //http.exceptionHandling().accessDeniedHandler(myAccessFail);
        //自定义403页面,前后端不分离
        http.exceptionHandling().accessDeniedPage("/noauth");
    }
    //==================
}

在这里插入图片描述

403处理器

package com.feng.securitydemo01.config;

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;

@Component
public class MyAccessFail implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        //设置响应状态码
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        //设置响应数据格式
        response.setContentType("application/json;charset=utf-8");
        //输入响应内容
        PrintWriter writer = response.getWriter();
        String json="{\"status\":\"403\",\"msg\":\"无权访问\"}";
        writer.write(json);
        writer.flush();

    }
}

package com.feng.securitydemo01.config;

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.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;

@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyAccessFail myAccessFail;
    
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()  //关闭csrf
                .formLogin()
//                .usernameParameter("自己根据情况写") 自定义表单的username,password
//                .passwordParameter("自己情况写")
            //还有rememberme、logout功能,极其简单,这里就不说了
                .loginProcessingUrl("/login")  //登录的url
                .successForwardUrl("/index")   //登录成功后走/index
                .and()
                .authorizeRequests().antMatchers("/","/index","/toLogin").permitAll()  //"/","/index"放行
                .anyRequest().authenticated(); //所有请求都需要认证
        
        //配置403处理器,修改response中的内容,前后端分离,是根据响应体来具体判断的。
        //http.exceptionHandling().accessDeniedHandler(myAccessFail);
        //自定义403页面,前后端不分离
        http.exceptionHandling().accessDeniedPage("/noauth");
    }
}

源码

https://download.csdn.net/download/okok__TXF/80962384

-前后端分离

如果前文误人子弟太多了,就不写了,这篇也删了。。。根据情况来写吧,

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security是一个用于身份验证和授权的框架,在Spring项目中提供了一套强大的安全性解决方案。以下是你入门Spring Security的步骤: 1. 添加Spring Security依赖:在你的项目中,通过Maven或Gradle添加Spring Security的依赖。例如,在Maven中,你可以添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 配置Spring Security:创建一个配置类来配置Spring Security。这个配置类需要继承`WebSecurityConfigurerAdapter`类,并覆盖`configure`方法。例如,你可以创建一个类叫做`SecurityConfig`: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() // 允许公共访问的URL .anyRequest().authenticated() // 其他URL需要身份验证 .and() .formLogin() // 启用表单登录 .loginPage("/login") // 自定义登录页面URL .permitAll() .and() .logout() // 启用注销 .permitAll(); } } ``` 上述配置中,我们定义了哪些URL是公开访问的,哪些URL需要身份验证,以及自定义了登录和注销的相关配置。 3. 创建用户服务:在上面的配置类中,你需要定义一个用户服务来获取用户的身份验证信息。这可以通过实现`UserDetailsService`接口来完成。你可以创建一个类叫做`UserService`来实现这个接口,并重写`loadUserByUsername`方法: ```java @Service public class UserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 从数据库或其他数据源中获取用户信息 // 然后返回一个实现了UserDetails接口的类,代表用户的身份验证信息 // 例如,你可以使用Spring Security提供的User类 return User.builder() .username(username) .password("password") .roles("USER") .build(); } } ``` 上述代码中,我们简单地返回了一个固定的用户信息,实际应用中你需要从数据库或其他数据源中获取真实的用户信息。 4. 配置密码编码器:为了安全起见,你需要对用户密码进行编码。在上述的配置类中,通过重写`configure`方法来配置密码编码器。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } // 其他配置... } ``` 上述代码中,我们使用了`BCryptPasswordEncoder`来对密码进行编码。 这些是入门Spring Security的基本步骤。当你完成了上述配置后,你的应用程序将需要进行身份验证,并且可以通过URL保护来限制访问。你可以根据需要进一步自定义和扩展Spring Security的功能。希望这能帮助到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值