OAuth 2.0是用于授权的行业标准协议。OAuth 2.0取代了在2006年创建的原始OAuth协议上所做的工作。OAuth 2.0专注于客户端开发人员的简单性,同时为Web应用程序,桌面应用程序,手机和客厅设备提供特定的授权流程。
开发工具:Idea
开发环境:jdk1.8 、maven3.5.0
springboot 2.1.3
1、点击【Create New Project】创建一个新的项目
选择【Spring Initializr】选择JDK1.8,然后点击Next
接下来填好对应的资料,点击Next:
然后选择Springboot2.1.3,然后勾选:
接下来点击Next
点击Finish开始项目的编写
我们开始一个项目的时候,首先要一步一步的去配置,不能一下盲目的去配置一大堆东西后去运行,这样如果出错了就很难排错,我们一步步去配置所要的框架然后去运行没问题了再去配置下一个。
我们先是安装Thymeleaf
加入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
然后去resources目录下面新建配置文件:application.yml
然后开始配置thymeleaf:
server:
port: 8888
#thymeleaf
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
cache: false
encoding: UTF-8
mode: LEAGCYHTML5
servlet:
content-type: text/html
然后我们再去创建Controller包和ApiController.class类去编写跳转
package com.oauth2.pan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @Author: Caiden(张志鑫)
* @Date: 2019/2/26 15:18
* @Version 0.0.1
*/
@Controller
@RequestMapping("/api")
public class ApiController {
@RequestMapping("/hello")
public ModelAndView sayHelloWorld(ModelAndView model){
model.setViewName("index");
return model;
}
}
然后在resources -> templates 目录下新建一个html文件:index.html。启动运行测试:
可以访问,说明我们thymeleaf框架搭建好了。
此刻我们的目录结构:
接下来搭建我们的oauth2认证,我们加入两个依赖包
<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.1.3.RELEASE</version>
</dependency>
需要注意的问题一:
1、当我们加入依赖包后可以在项目的External Libraries看下jar包是不是已经被加入到项目里面,有些时候Jar已经通过Maven下载完成,但是没有导入进来。
2、打开File->Project Structure -》Project Settings -> Libraries 中看oauth2的jar包是否有加载进来,如果下图中绿色框框中是红色,请确保MAVEN下载JAR包成功的情况下,删除classes中的信息,再点击绿色框上边最左边的“+”号,选择MAVEN下载好的jar包即可
当上面提到的两个依赖jar包确认下载并加载成功后,开始进行认证编码:
WebSecurityConfigurerAdapter是默认情况下Spring security的http配置;ResourceServerConfigurerAdapter是默认情况下spring security oauth 的http配置。
(WebSecurityConfigurerAdapter的配置拦截要优先于ResourceServerConfigurerAdapter,优先级高的http配置是可以覆盖优先级低的配置的)
先覆写spring Security的http配置
新建类名:WebSecurityConfiguration 然后去继承 WebSecurityConfigurerAdapter
老司机避坑指南:解决 There is no PasswordEncoder mapped for the id "null")
SpringBoot升级到了2.0之后的版本,Security也由原来的版本4升级到了5
升到5版本之后的security必须加入密码加密
WebSecurityConfiguration.class
package com.oauth2.pan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Author: Caiden(张志鑫)
* @Date: 2019/2/26 15:57
* @Version 0.0.1
*/
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")
.and()
.authorizeRequests()
.antMatchers("/oauth/**").authenticated()
.and()
.formLogin().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
auth.inMemoryAuthentication().passwordEncoder(encoder)
.withUser("admin")
.password(encoder.encode("admin1234")).roles("USER");
}
/**
* 需要配置这个支持password模式
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 密码加密
* */
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
再去覆写Oauth2的http配置类
ResourceServerConfig.class
package com.oauth2.pan.config.oauth2;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
/**
* @Author: Caiden(张志鑫)
* @Date: 2019/2/26 16:07
* @Version 0.0.1
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String PAN_RESOURCE_ID = "*";
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(PAN_RESOURCE_ID);
}
}
再去新建一个认证服务器:
AuthorizationServerConfiguration.class
package com.oauth2.pan.config.oauth2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
/**
* @Author: Caiden(张志鑫)
* @Date: 2019/2/26 16:10
* @Version 0.0.1
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerSecurityConfigurer security)throws Exception {
security.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//添加客户端信息
//使用内存存储OAuth客户端信息
clients.inMemory()
// client_id
.withClient("test")
// 该client允许的授权类型,不同的类型,则获得token的方式不一样。
.authorizedGrantTypes("password")
// client_secret
.secret(encoder.encode("123456"))
.resourceIds("*")
// 允许的授权范围
.scopes("all")
.accessTokenValiditySeconds(1000) //token过期时间
.refreshTokenValiditySeconds(1000); //refresh过期时间;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)throws Exception {
//reuseRefreshTokens设置为false时,每次通过refresh_token获得access_token时,也会刷新refresh_token;也就是说,会返回全新的access_token与refresh_token。
//默认值是true,只返回新的access_token,refresh_token不变。
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager);
}
@Bean
public TokenStore tokenStore() {
//token保存在内存中(也可以保存在数据库、Redis中)。
//如果保存在中间件(数据库、Redis),那么资源服务器与认证服务器可以不在同一个工程中。
//注意:如果不保存access_token,则没法通过access_token取得用户信息
return new InMemoryTokenStore();
}
}
好了,都配置好了,万事OK,快去测试一下吧。
关于分享有何疑问与建议欢迎留言哦!
如果你对Spring有兴趣,实训邦精心准备了Spring2.0的深度技术讲解。
可以通过链接学习更多SpringBoot+Vue前后端分离的内容。