SpringSecurity(一)

在我们的业务处理中,对于安全的管理是必不可少的,也就是认证以及权限,在Spring横行的今天,学习如何使用SpringSecurity是必不可少的,所以最近想深入学习一下SpringSecurity并分享一下自己的学习历程,此次的学习主要以实践+部分源码为主,完成认证+权限+Oauth2+JWT+oos等,最后会做一个demo,来完成此次的SpringSecurity之旅。

简介

Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的 Bean,充分利用了 Spring IoC ,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。主要实现了认证(用户登录)和授权(资源调用)。

具体实现与部分源码分析

不进行任何处理

1、添加依赖

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

2、写一个登录的controller

@Controller
public class LoginController {
   

    @RequestMapping("/login")
    public String login(){
   
        System.out.println("进行登录中");
        return "redirect:main.html";
    }
}

3、创建登录页和主页

<!--login.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="post">
        用户:<input type="text" name="username">
        密码:<input type="password" name="password">
        <input type="submit" value="提交">
    </form>
</body>
</html>

<!--main.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    登录成功
</body>
</html>

4、启动项目测试,访问http://localhost:8080/login.html

启动后访问一个官方提供的页面,用户名默认为user,密码为启动时控制台打印的Using generated security password。

Using generated security password: 90e4c13a-3e17-435a-9835-9a5c6088117f

输入可以正常访问。

认证的进阶(一)

上面这样的处理,很显然是不满足我们在业务中的处理的,我们需要自己的登录页面,也需要有自己的验证逻辑。接下来先从验证逻辑方面说起。

首先我们需要认识一个接口UserDetailsService

public interface UserDetailsService {
   
	//通过username加载一个User,此处的var1即为前端传过来的username.
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

可以看出该方法返回了一个UserDetails,让我们继续看一下这个东东是啥

public interface UserDetails extends Serializable {
   
    //获取该用户的所有权限
    Collection<? extends GrantedAuthority> getAuthorities();
	//获取密码
    String getPassword();
	//获取用户名
    String getUsername();
	//判断账户是否过期
    boolean isAccountNonExpired();
	//判断账户是否锁定
    boolean isAccountNonLocked();
	//判断凭证(密码)是否过期
    boolean isCredentialsNonExpired();
	//判断账户是否可用
    boolean isEnabled();
}

可以看出它是一个用来存储,账户信息的一个类(它存储的是用户的正确的信息,比如从数据库里查出的),我们继续看一下它的实现类User

public class User implements UserDetails, CredentialsContainer {
   
    private static final long serialVersionUID = 550L;
    private static final Log logger = LogFactory.getLog(User.class);
    private String password;//密码
    private final String username;//用户名
    private final Set<GrantedAuthority> authorities;//权限
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;

    public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
   
        this(username, password, true, true, true, true, authorities);
    }
	//此处为构造方法,进行一个参数的填充,在业务中可以将从数据库查询到的数据放入User对象中。
    public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
   
        //如果username和password为空,则抛出Cannot pass null or empty values to constructor
        Assert.isTrue(username != null && !"".equals(username) && password != null, "Cannot pass null or empty values to constructor");
        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
	.....
   }

这里还需要说一个PasswordEncoder接口,它是用于对密码进行一个加密,对比。

public interface PasswordEncoder {
   
    //对var1进行加密,使用的是
    String encode(CharSequence var1);
	//对密码进行比对,var1为原生密码,var2为加密后的密码
    boolean matches(CharSequence var1, String var2);
	
    //是否进行了二次加密
    default boolean upgradeEncoding(String encodedPassword) {
   
        return false;
    }
}

官方推荐使用的实现类为BCryptPasswordEncoder,对其加密方式感兴趣的话,可以看看其源码。

如果对以上的俩种类不清楚的话,看一下接下来的实现逻辑就知道他的作用了。

承接上面的代码。

1、进行配置

@Configurat
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值