主要参考了
https://blog.csdn.net/u013034378/article/details/86622590
部分参考了
https://blog.csdn.net/lightofmiracle/article/details/79151074
关于oauth2.0的概念以及相关的知识等可以建议参阅理解OAuth 2.0。
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.6.RELEASE
com.chenclass
oauthserver
0.0.1-SNAPSHOT
oauthserver
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.security.oauth
spring-security-oauth2
2.3.4.RELEASE
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
package com.chenclass.oauthserver.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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//配置用户存储在内存中,可以设置用户账号、密码、角色等
@Override
protected UserDetailsService userDetailsService(){
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password(new BCryptPasswordEncoder().encode("123456"))
.roles("USER").build());
manager.createUser(User.withUsername("admin").password(new BCryptPasswordEncoder().encode("123456"))
.roles("ADMIN").build());
return manager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//将用户信息添加认证管理中,这里有两种方式
//方法一:
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
//方法二:
//auth.inMemoryAuthentication().withUser("user1").password(passwordEncoder().encode("123456")).roles("user");
}
/*
* 进行HTTP配置拦截,过滤url,这里主要配置服务端的请求拦截
* permitAll表示该请求任何人都可以访问,authenticated()表示其他的请求都必须要有权限认证
* 本例子中,以下配置用不到,也可以省略,因为本文使用了4中ResourceServerConfig,
* 导致该例子会用ResourceServerConfig中的拦截配置*/
// @Override
// public void configure(HttpSecurity http) throws Exception {
// http.formLogin()
// .loginPage("/login.html")
// .loginProcessingUrl("/login")
// .and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID").permitAll()
// .and().authorizeRequests()
// .antMatchers("/login.html").permitAll()
// .anyRequest().authenticated()
// .and().csrf().disable();
// }
/**
* spring5.x 需要注入一个PasswordEncoder,否则会报这个错There is no PasswordEncoder mapped for the id \"null\"
* 加了密码加密,所有用到的密码都需要这个加密方法加密
* @return
*/
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 需要配置这个支持password模式
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
package com.chenclass.oauthserver.config;
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;
@Configuration
@EnableResourceServer
/**
* 这里设置访问路径权限,相当于客户端url权限拦截,是可以单独独立出来
*/
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("ADMIN","USER")
.antMatchers("/test").authenticated()
.anyRequest().authenticated();
}
}
package com.chenclass.oauthserver.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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;
@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
/**
* 用来配置令牌端点(Token Endpoint)的安全约束.
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.realm("oauth2-resource")
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
/**
* 用来配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化,能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
* clientId:(必须的)用来标识客户的Id。
* secret:(需要值得信任的客户端)客户端安全码,如果有的话。
* redirectUris 返回地址,可以理解成登录后的返回地址,可以多个。应用场景有:客户端swagger调用服务端的登录页面,登录成功,返回客户端swagger页面
* authorizedGrantTypes:此客户端可以使用的权限(基于Spring Security authorities)
authorization_code:授权码类型、implicit:隐式授权类型、password:资源所有者(即用户)密码类型、
client_credentials:客户端凭据(客户端ID以及Key)类型、refresh_token:通过以上授权获得的刷新令牌来获取新的令牌。
* scope:用来限制客户端的访问范围,如果为空(默认)的话,那么客户端拥有全部的访问范围。
* accessTokenValiditySeconds token有效时长
* refreshTokenValiditySeconds refresh_token有效时长
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("demoClient")
.secret(new BCryptPasswordEncoder().encode("demoSecret"))
.redirectUris("")
.authorizedGrantTypes("authorization_code","client_credentials", "password", "refresh_token")
.scopes("all")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(60*60)
.refreshTokenValiditySeconds(60*60);
}
/**
* 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)。
* 访问地址:/oauth/token
* 属性列表:
* authenticationManager:认证管理器,当你选择了资源所有者密码(password)授权类型的时候,需要设置为这个属性注入一个 AuthenticationManager 对象。
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//设置认证管理器
endpoints.authenticationManager(authenticationManager);
//设置访问/oauth/token接口,获取token的方式
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
}
}
package com.chenclass.oauthserver.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("")
public class TestController {
@RequestMapping(value = "/test",method = RequestMethod.GET)
public Object test(){
return "test";
}
@RequestMapping(value = "/user",method = RequestMethod.GET)
@PreAuthorize("hasAnyRole('ROLE_USER')") //注解验证时默认加上前缀ROLE_,原因后面文章再讲
public Object user(){
return "user";
}
@RequestMapping(value = "/user/a",method = RequestMethod.GET)
public Object user2(){
return "user";
}
@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@RequestMapping(value = "/admin",method = RequestMethod.GET)
public Object admin(){
return "admin";
}
@RequestMapping(value = "/admin/b",method = RequestMethod.GET)
public Object admin2(){
return "admin";
}
}
localhost:8080/test
localhost:8080/oauth/token?grant_type=password&client_id=demoClient&client_secret=demoSecret&username=admin&password=123456
Basic ZGVtb0NsaWVudDpkZW1vU2VjcmV0
头内容为:bearer cdfd17e7-ebac-4ca2-be5c-b493b28b9850,地址为localhost:8080/test
(1)
(2)
(3)
(4)