创建项目

先创建一个spring项目。

然后编写pom文件如下,引入spring-boot-starter-security,我这里使用的spring boot是2.4.2,这里使用使用spring-boot-dependencies,在这里就能找到对应的security的包。

<?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>
<groupId>com.example</groupId>
<artifactId>app-kiba-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>app-kiba-security</name>
<description>app-kiba-security</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
</properties>
<dependencies>
<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> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> </dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.kiba.appkibasecurity.AppKibaSecurityApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> </project>

然后访问创建项目时默认生成的接口:http://127.0.0.1:8080/user/123/roles/222,得到如下界面。

这是相当于,在我们的接口请求的前面做了一个拦截,类似filter,拦截后,跳转到了一个界面,让我们输入账号密码。这里,我由于没有设置账号密码,所以登录不进去。

设置访问一

下面设置一个账号密码,并且设置hello接口可以直接访问,设置很简单,就是注入两个bean,InMemoryUserDetailsManager和WebSecurityCustomizer,代码如下:

@Configuration
public class SecurityConfig {
/**
* 注册用户,这里用户是在内存中的
* {noop}表示“无操作”(No Operation)密码编码。
* @return
*/
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
users.createUser(User.withUsername("kiba").password("{noop}123").roles("admin").build());
return users;
} /**
* 让hello可以不用登录,就可以直接访问,例如:http://127.0.0.1:8080/hello?name=kiba就可以直接访问
* @return
*/
@Bean
WebSecurityCustomizer webSecurityCustomizer() {
return new WebSecurityCustomizer() {
@Override
public void customize(WebSecurity web) {
web.ignoring().antMatchers("/hello");
}
};
} }

现在我们访问http://127.0.0.1:8080/user/123/roles/222,进入到登录页面,输入kiba/123就可以查看接口执行的结果了。

http://127.0.0.1:8080/hello?name=kiba就无需登录,可以直接访问。

登录一次,其他接口就可以自由访问了

控制请求

现在,增加一个类SecurityAdapter,继承自WebSecurityConfigurerAdapter。然后重写他的configure方法

@Configuration
@AllArgsConstructor
public class SecurityAdapter extends WebSecurityConfigurerAdapter { /**
* authenticated():用户需要通过用户名/密码登录,记住我功能也可以(remember-me)。
* fullyAuthenticated()用户需要通过用户名/密码登录,记住我功能不行。
*/
@Override
@SneakyThrows
protected void configure(HttpSecurity http) {
http.httpBasic().and()
//禁用跨站请求伪造(CSRF)保护。
.csrf().disable()
.authorizeRequests().anyRequest().fullyAuthenticated();
} }

当使用,增加了SecurityAdapter后,我们重新请求http://127.0.0.1:8080/user/123/roles/222,得到界面如下:

可以看到,登录界面的样式被美化了。

设置访问二(推荐)

我们还可以使用第二种方法,来做用户密码的配置。

通过重写configure(AuthenticationManagerBuilder auth)函数,来创建用户,这种方式创建用户会将前面的bean-UserDetailsService给覆盖,即,用户只剩下这里创建的。

代码如下:

@Configuration
@AllArgsConstructor
public class SecurityAdapter extends WebSecurityConfigurerAdapter { /**
* authenticated():用户需要通过用户名/密码登录,记住我功能也可以(remember-me)。
* fullyAuthenticated()用户需要通过用户名/密码登录,记住我功能不行。
*/
@Override
@SneakyThrows
protected void configure(HttpSecurity http) {
http.httpBasic().and()
//禁用跨站请求伪造(CSRF)保护。
.csrf().disable()
.authorizeRequests().anyRequest().fullyAuthenticated();
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("kiba518")
.password(passwordEncoder().encode("123"))
.authorities(new ArrayList<>(0));
} @Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} }

这里的用户是写死的,用户是可以修改成读取数据库的信息的。

我们查看WebSecurityConfigurerAdapter的代码,可以看到他有注解@Order(100),数越大,执行越优先级越低,即,他的执行顺序是相对比较靠后的。

授权OAuth2

授权这个设计理念是这样,它是结合上面的security的操作,实现了一个普通的WebApp转换成授权服务器WebApp。

授权服务器转换思路

我们先了解一下security转授权服务器的思路。

1,在这个应用里,创建一个auth接口,然后任何人想访问这个接口,就都需要输入账户密码了。

2,我们这个auth接口的返回值是个code,然后我们的前端,或者其他调用接口的APP,就可以把这个code作为用户登录的token了,。

3,然后我们再做一个接口,接受一个token参数,可以验证token是否有效。

这样我们这个授权服务器的搭建思路就构建完成了。

但按这个思路,我们需要做很多操作,比如创建接口,缓存token等等,现在spring提供了一个Oauth2的包,他可以帮我们实现这些接口定义。

OAuth2的接口如下,可以自行研究。

/oauth/authorize:授权端点

/oauth/token:获取令牌端点

/oauth/confirm_access:用户确认授权提交端点

/oauth/error:授权服务错误信息端点

/oauth/check_token:用于资源服务访问的令牌解析端点

/oauth/token_key:提供公有密匙的端点,如果使用JWT令牌的话

实现授权服务器

现在我们实现一个授权服务器。

先添加OAuth2的引用。

 <dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>

然后增加配置文件AuthorizationConfig。

@Configuration
@EnableAuthorizationServer //开启授权服务
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { @Autowired
private PasswordEncoder passwordEncoder; @Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//允许表单提交
security.allowFormAuthenticationForClients()
.checkTokenAccess("isAuthenticated()");
} @Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-kiba") //客户端唯一标识(client_id)
.secret(passwordEncoder.encode("kiba518-123456")) //客户端的密码(client_secret),这里的密码应该是加密后的
.authorizedGrantTypes("password") //授权模式标识,共4种模式[授权码(authorization-code)隐藏式(implicit) 密码式(password)客户端凭证(client credentials)]
.scopes("read_scope"); //作用域 } @Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
} }

然后打开SecurityAdapter,增加一个bean,如下,目的是让上面的AuthorizationConfig里Autowired的authenticationManager可以实例化。

@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}

然后使用APIFox调用一下/oauth/token接口。

先选择auth,输入账号密码,这个账号密码就是AuthorizationConfig里配置的客户端id和密码。

这个数据在请求时,会进行base64编码,然后以http的header属性Authorization的值的模式传递,如下。

然后输入参数,参数里scope和grant_type要和AuthorizationConfig里定义的scopes和authorizedGrantTypes一样,如下。

请求后,得到结果,如上图。

我们得到"access_token": "19d37af2-6e13-49c3-bf19-30a738b56886"。

有了access_token后,我们的前端其实就已经可以进行各种骚操作了。

资源服务

这个是Oauth为我们提供的一项很好用的功能。

我们创建一个项目做为资源服务。

添加依赖,版本与上面相同。

  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>

然后编写资源配置,代码如下:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Bean
public RemoteTokenServices remoteTokenServices() {
final RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("client-kiba");
tokenServices.setClientSecret("kiba518-123456");
tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");//这个接口是oauth自带的
return tokenServices;
} @Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.stateless(true);
} @Override
public void configure(HttpSecurity http) throws Exception {
//session创建策略
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
//所有请求需要认证
http.authorizeRequests().anyRequest().authenticated();
}
}

因为添加了spring-boot-starter-security,所以,我们请求这个资源WebApp,就都需要输入账号密码。

但因为,我们配置了ResourceServerConfig,这里我们配置了远程token服务,设置的信息是我们上面创建授权服务的信息。所以,在访问这个WebApp时,我们提供token即可。

使用APIFOX测试,先添加auth的token,内容是来自于上面,/oauth/token的返回值access_token的值。

然后请求user接口,我这user接口没有参数,请求结果如下:

总结

这个授权服务挺好用的,就是配置太繁琐了,初学者不太好理解,而且功能太多,配置太闹心。

这个资源服务还是很贴心的,他提我们实现了,tokencheck的部分,但要注意的是,他这tokencheck是基于http请求的。

虽然Oath很好用,但,我还是觉得,这个认证部分自己写比较好,我们可以根据项目的需求,设计轻量级的授权认证。

比如,我们想减少http请求,把部分tokencheck在缓存内进行check,那使用oauth时,修改起来就会很头疼。如果是自己写的授权服务器,就不会有修改困难的问题。


注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!



若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

https://www.cnblogs.com/kiba/p/18252859

SpringBoot的Security和OAuth2的使用的更多相关文章

  1. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

  2. springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)

    项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖  ...

  3. Spring Security基于Oauth2的SSO单点登录怎样做?一个注解搞定

    一.说明 单点登录顾名思义就是在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统,免除多次登录的烦恼.本文主要介绍 同域 和 跨域 两种不同场景单点登录的实现原理,并使用 Spring ...

  4. SpringBoot集成security

    本文就SpringBoot集成Security的使用步骤做出解释说明.

  5. SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能

    在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...

  6. SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证

    整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...

  7. Spring Security 与 OAuth2 介绍

    个人 OAuth2 全部文章 Spring Security 与 OAuth2(介绍):https://www.jianshu.com/p/68f22f9a00ee Spring Security 与 ...

  8. security和oauth2.0的整合

    security和oauth2.0的整合 之前已经介绍过security的相关的介绍,现在所需要做的就是security和oauth2.0的整合,在原有的基础上我们加上一些相关的代码;代码实现如下: ...

  9. Spring Security 与 OAuth2(介绍)

    https://www.jianshu.com/p/68f22f9a00ee Spring Security 与 OAuth2(介绍) 林塬 2018.01.23 11:14* 字数 3097 阅读 ...

  10. springboot使用security

    springboot使用security 1.结构图 2.pom.xml <?xml version="1.0" encoding="UTF-8"?> ...

随机推荐

  1. [FAQ] Pytorch PytorchStreamReader failed reading zip archive

    比如:rm -rf ~/.cache/huggingface Tool:ChatAI Link:https://www.cnblogs.com/farwish/p/17290240.html

  2. Roslyn 分析器 EnforceExtendedAnalyzerRules 属性的作用

    在开始编写 dotnet 的 Roslyn 分析器项目时,会被 VisualStudio 通过 RS1036 要求在项目文件配置上 EnforceExtendedAnalyzerRules 属性,本文 ...

  3. LLaMA 3 源码解读-大语言模型5

    本来不是很想写这一篇,因为网上的文章真的烂大街了,我写的真的很有可能没别人写得好.但是想了想,创建这个博客就是想通过对外输出知识的方式来提高自身水平,而不是说我每篇都能写得有多好多好然后吸引别人来看. ...

  4. docker-compose搭建的Mysql主从复制

    设置前注意下面几点: 1)要保证同步服务期间之间的网络联通.即能相互ping通,能使用对方授权信息连接到对方数据库(防火墙开放3306端口). 2)关闭selinux. 3)同步前,双方数据库中需要同 ...

  5. cesium教程8-官方示例翻译-图层亮度对比度调整

    完整示例代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="u ...

  6. cesium问题-关于不同时间模型亮度不一致问题

    项目中遇到发布的bim模型在当天不同时间的模型亮度发生变化,尤其是晚上的时候会出现模型很暗.尴了个尬,一度怀疑是自己眼睛有问题,连续几天出现同样的情况,想到可能是时间问题导致的模型亮度不同,于是测试了 ...

  7. VNC 远程桌面很卡,替代方案如下

    VNC 远程桌面是一款古老的远程桌面软件,是基于 Unix 和 Linux 操作系统的免费的开源软件.免费开源很好,但是 VNC 也存在一些缺点. 1.VNC 远程桌面很卡 想白嫖 VNC,就要接受卡 ...

  8. 密码学—Vigenere加密Python程序

    文章目录 维吉尼亚加密 加密算法 解密算法 注意事项 维吉尼亚加密 古典密码,属于多表加密. 怎么就是多表了? 维吉尼亚密码的加密算法实质是凯撒密码,因为他是先分好小组,然后用密钥串对应着分好组的每一 ...

  9. LLM实战:当网页爬虫集成gpt3.5

    1. 背景 最近本qiang~关注了一个开源项目Scrapegraph-ai,是关于网页爬虫结合LLM的项目,所以想一探究竟,毕竟当下及未来,LLM终将替代以往的方方面面. 这篇文章主要介绍下该项目, ...

  10. 23ai免费版本环境快速就绪

    笔者感受就是搞一套Oracle 23ai的学习测试环境,从未如此的简单高效. 因为近期Oracle 23ai这个话题很火,很多人也在找实验环境想亲自体验测试一番. 其实搞这样的环境没有任何的门槛,甚至 ...