- 摘要:本文中已OAuth2.0授权码模式为案例,将认证授权流程分化并一一解析,最终已代码的形式展现讲解。
一 数据库
##======================= Spring Security OAuth协议/官网给出的表结构=======================##
## 用来存储用户认证信息
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端标 识',
`resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接入资源列表',
`client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '客户端秘钥',
`scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色权限范围',
`authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '可用的授权的类型',
`web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'web端服务地址',
`authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`access_token_validity` int(11) NULL DEFAULT NULL COMMENT 'token有效时长',
`refresh_token_validity` int(11) NULL DEFAULT NULL COMMENT 'token刷新后的有效时长',
`additional_information` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`archived` tinyint(4) NULL DEFAULT NULL,
`trusted` tinyint(4) NULL DEFAULT NULL,
`autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '接入客户端信息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('c1', 'res1', '$2a$10$yOELhJjTEmOrEAkgDHJTCO25FJXTnA3/GcjZAkPMbq.0bBK74RgL.', 'ROLE_ADMIN,ROLE_USER,ROLE_API', 'client_credentials,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', NULL, 7200, 259200, NULL, '2020-10-14 17:27:07', 0, 0, 'false');
INSERT INTO `oauth_client_details` VALUES ('c2', 'res2', '$2a$10$yOELhJjTEmOrEAkgDHJTCO25FJXTnA3/GcjZAkPMbq.0bBK74RgL.', 'ROLE_API', 'client_credentials,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', NULL, 31536000, 2592000, NULL, '2020-10-14 17:27:09', 0, 0, 'false');
## 用于保存生成的code信息
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成code',
`authentication` blob NULL COMMENT '用户信息',
INDEX `code_index`(`code`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
##======================= 用户/角色/权限(可自定义)=======================##
## 许可/权限信息
DROP TABLE IF EXISTS `t_permission`;
CREATE TABLE `t_permission` (
`id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限标识符',
`description` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`url` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求地址',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_permission` VALUES ('1', 'p1', '测试资源 1', '/r/r1');
INSERT INTO `t_permission` VALUES ('2', 'p3', '测试资源2', '/r/r2');
## 角色信息
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
`update_time` datetime(0) NULL DEFAULT NULL,
`status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `unique_role_name`(`role_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_role` VALUES ('1', '管理员', NULL, NULL, NULL, '');
## 角色/许可 关联信息
DROP TABLE IF EXISTS `t_role_permission`;
CREATE TABLE `t_role_permission` (
`role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`permission_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`role_id`, `permission_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_role_permission` VALUES ('1', '1');
INSERT INTO `t_role_permission` VALUES ('1', '2');
## 用户信息
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL COMMENT '用户id',
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`fullname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户姓名',
`mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_user` VALUES (10000, '孔超', '$2a$10$aFsOFzujtPCnUCUKcozsHux0rQ/3faAHGFSVb9Y.B1ntpmEhjRtru', '孔超', '15062100336');
## 用户/角色关联信息
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role` (
`user_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
`creator` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`user_id`, `role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_user_role` VALUES ('1', '1', NULL, NULL);
一 认证服务器
认证服务器端授权服务管理类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import javax.sql.DataSource;
import java.util.Arrays;
/**
* 授权服务管理
* 1 通过链接获取的认证信息与库中的许可信息进行比对验证
* 2 设置令牌的使用配置
* 3 设置认证模式
* @author kongc
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Autowired
private JwtAccessTokenConverter accessTokenConverter;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 将客户端信息存储到数据库
*/
@Bean
public ClientDetailsService clientDetailsService(DataSource dataSource) {
ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder);
return clientDetailsService;
}
/**
* 配置客户端详情
* 指定授权服务支持哪些客户端
* 可以通过写死客户端令牌或调用数据库中的信息来进行判断
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//第二种:从数据库中获取授权配置
clients.withClientDetails(clientDetailsService);
/**
//第一种:使用in-memory存储
clients.inMemory()
//client_id
.withClient("c1")
//客户端密钥
.secret(new BCryptPasswordEncoder().encode("secret"))
//资源列表,资源id
.resourceIds("res1")
//该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
.authorizedGrantTypes("password", "authorization_code", "client_credentials", "implicit", "refresh_token")
//允许的授权范围(all/read/服务name)
.scopes("all")
//false跳转到授权页面
.autoApprove(false)
//加上验证回调地址
.redirectUris("http://www.baidu.com");
*/
}
/**
* 管理令牌
* 配置令牌访问端点(配置申请令牌的url)
* 配置令牌服务(配置令牌生成、发放)
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
//认证管理器(密码模式需要)
.authenticationManager(authenticationManager)
//授权码服务(授权模式需要)
.authorizationCodeServices(authorizationCodeServices)
//令牌管理服务
.tokenServices(tokenService())
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
/**
* 配置令牌访问端点的安全约束
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
//oauth/token_key是公开
.tokenKeyAccess("permitAll()")
//oauth/check_token公开
.checkTokenAccess("permitAll()")
//表单认证(申请令牌)
.allowFormAuthenticationForClients();
}
/**======================================== 本地方法 ============================================**/
/**
* 令牌管理服务
* @return
*/
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service=new DefaultTokenServices();
//客户端详情服务
service.setClientDetailsService(clientDetailsService);
//支持刷新令牌
service.setSupportRefreshToken(true);
//令牌存储策略
service.setTokenStore(tokenStore);
//令牌增强
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
service.setTokenEnhancer(tokenEnhancerChain);
// 令牌默认有效期2小时
service.setAccessTokenValiditySeconds(7200);
// 刷新令牌默认有效期3天
service.setRefreshTokenValiditySeconds(259200);
return service;
}
/**
* 从数据库中获取授权码
*/
@Bean
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
//设置授权码模式的授权码如何存取
return new JdbcAuthorizationCodeServices(dataSource);
}
/**
* 设置授权码模式的授权码如何存取,暂时采用内存方式
* @return
*/
/**
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
*/
}
令牌配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
/**
* 令牌配置
* 根据私钥生成JWT令牌(token)
* 配置JWT令牌的存储方式
* @author kongc
*/
@Configuration
public class TokenConfig {
private String SIGNING_KEY = "KONG3672CHAO757";
/**
* 将令牌已JWT的形式存储,并通过对称密钥来保证令牌的有效性
* JWT令牌存储方案
* @return
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//对称秘钥,资源服务器使用该秘钥来验证
converter.setSigningKey(SIGNING_KEY);
return converter;
}
/**
* 将普通令牌存储至内存中
* @return
*/
/* @Bean
public TokenStore tokenStore() {
//第一种:使用内存存储令牌(普通令牌)
return new InMemoryTokenStore();
}*/
}
安全路径拦截类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 安全路径拦截
* @author Administrator
**/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 认证管理器
*/
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 密码编码器
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 安全拦截机制(最重要)
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/r/r1").hasAnyAuthority("p1")
.antMatchers("/r/r2").hasAnyAuthority("p2")
.antMatchers("/login*").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
Spring Security 提供的获取用户信息类
/**
* @author Administrator
* @version 1.0
**/
@Service
public class SpringDataUserDetailsService implements UserDetailsService {
@Autowired
UserDao userDao;
/**
* 根据 账号查询用户信息
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//将来连接数据库根据账号查询用户信息
UserDto userDto = userDao.getUserByUsername(username);
if(userDto == null){
//如果用户查不到,返回null,由provider来抛出异常
return null;
}
//根据用户的id查询用户的权限
List<String> permissions = userDao.findPermissionsByUserId(userDto.getId());
//将permissions转成数组
String[] permissionArray = new String[permissions.size()];
permissions.toArray(permissionArray);
//将userDto转成json
String principal = JSON.toJSONString(userDto);
UserDetails userDetails = User.withUsername(username).password(userDto.getPassword()).authorities(permissionArray).build();
return userDetails;
}
}
与数据库交互获取用户详情类:
import com.oauth.authentication.data.Data;
import com.oauth.authentication.model.PermissionDto;
import com.oauth.authentication.model.UserDto;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
/**
* @author Administrator
* @version 1.0
**/
@Repository
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
/**
* 根据账号查询用户信息
* 测试账户:kongchao/123456
*/
public UserDto getUserByUsername(String username){
//模拟连接数据库获取用户信息
if(!StringUtils.isBlank(username) && username.equals(Data.name)){
return Data.getUser();
}else{
return null;
}
}
/**
* 根据用户id查询用户权限
*/
public List<String> findPermissionsByUserId(String userId){
//模拟连接数据库获取用户信息
if(!StringUtils.isBlank(userId) && userId.equals(Data.id)){
List<PermissionDto> list = Data.getPermission(userId);
List<String> permissions = new ArrayList<>();
list.forEach(c -> permissions.add(c.getCode()));
return permissions;
}else{
return null;
}
}
}
数据库数据模拟类
import com.oauth.authentication.model.PermissionDto;
import com.oauth.authentication.model.UserDto;
import org.apache.commons.lang.StringUtils;
import java.util.*;
/**
1. 模拟数据库数据
2. @author kongc
*/
public class Data {
public static String name = "kongchao";
public static String id = "10000";
public static UserDto getUser(){
UserDto user = new UserDto();
user.setFullname("孔超");
user.setId("10000");
//$2a$10$aFsOFzujtPCnUCUKcozsHux0rQ/3faAHGFSVb9Y.B1ntpmEhjRtru == 123
user.setPassword("$2a$10$aFsOFzujtPCnUCUKcozsHux0rQ/3faAHGFSVb9Y.B1ntpmEhjRtru");
user.setUsername("kongchao");
user.setMobile("15062100336");
return user;
}
public static List<PermissionDto> getPermission(String userId){
if(!StringUtils.isBlank(userId) && userId.equals(id)){
PermissionDto permissionDto1 = new PermissionDto();
permissionDto1.setId("1");
permissionDto1.setCode("p1");
permissionDto1.setDescription("测试资源一");
permissionDto1.setUrl("/r/r1");
PermissionDto permissionDto2 = new PermissionDto();
permissionDto2.setId("1");
permissionDto2.setCode("p2");
permissionDto2.setDescription("测试资源二");
permissionDto2.setUrl("/r/r2");
List<PermissionDto> list = new ArrayList<>();
list.add(permissionDto1);
list.add(permissionDto2);
return list;
}else{
return null;
}
}
}
二 客户端(第三方)
资源服务访问配置
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.http.SessionCreationPolicy;
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;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* 资源服务访问配置
* 核对资源编号(RESOURCE_ID),认证用户授权许可的时会匹配当前客户端是否有使用该资源的权限,该数据可在‘oauth_client_details’表中核对
* 令牌解析方案:获取到的令牌通过本地解析或是调用认证服务器的check_token接口解析,可以自行配置。建议本地解析,调用远程接口效率太低。
* 拦截请求并验证权限是否可用:拦截请求,并根据解析后的用户许可信息判断当前与用户是否有权限调用哪些接口。
*/
@Configuration
@EnableResourceServer
public class ResouceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "res1";
@Autowired
TokenStore tokenStore;
/**
* 令牌解析方案
* @param resources
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
//资源 id
.resourceId(RESOURCE_ID)
//通过JWT对称密钥来解析token信息,从而获取用户信息(客户端/第三方)
.tokenStore(tokenStore)
//验证令牌的服务
//默认token解析方案(通过调用认证服务器check_token接口使用token解析用户信息/认证服务器)
/*.tokenServices(tokenService())*/
.stateless(true);
}
/**
* 拦截请求并验证权限是否可用
* @param http
* @throws Exception
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").access("#oauth2.hasScope('ROLE_API')")
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
/**
* 默认token解析方案(通过调用认证服务器check_token接口使用token解析用户信息
* 资源服务令牌解析服务
*/
/*@Bean
public ResourceServerTokenServices tokenService() {
//使用远程服务请求授权服务器校验token,必须指定校验token 的url、client_id,client_secret
RemoteTokenServices service=new RemoteTokenServices();
service.setCheckTokenEndpointUrl("http://localhost:53000/auth/oauth/check_token");
service.setClientId("c1");
service.setClientSecret("secret");
return service;
}*/
}
令牌解析配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
/**
* 令牌解析配置
* 根据私钥生成JWT令牌(token)
* 配置JWT令牌的存储方式
* @author kongc
*/
@Configuration
public class TokenConfig {
private String SIGNING_KEY = "KONG3672CHAO757";
/**
* 将令牌已JWT的形式存储,并通过对称密钥来保证令牌的有效性
* JWT令牌存储方案
* @return
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//对称秘钥,资源服务器使用该秘钥来验证
converter.setSigningKey(SIGNING_KEY);
return converter;
}
/**
* 将普通令牌存储至内存中
* @return
*/
/* @Bean
public TokenStore tokenStore() {
//第一种:使用内存存储令牌(普通令牌)
return new InMemoryTokenStore();
}*/
}
拦截求情/验证权限
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
/**
* 拦截求情/验证权限
* 注:这里的拦截和ResouceServerConfig类中的configure拦截方法不同,
* 这里拦截的是具体用户是否有权限使用某个接口,而ResouceServerConfig中则是规定了,
* 某个角色可以使用的权限范围,也就是说这里配置会细化到具体接口。
* @author Administrator
* @version 1.0
**/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 安全拦截机制(最重要)
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
//.antMatchers("/r/r1").hasAuthority("p2")
//.antMatchers("/r/r2").hasAuthority("p2")
//所有/r/**的请求必须认证通过
.antMatchers("/r/**").authenticated()
//除了/r/**,其它的请求可以访问
.anyRequest().permitAll();
}
}
Controller 资源访问测试类
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 认证授权-客户端
* @author kongc
*/
@RestController
@RequestMapping("/r")
public class OrderController {
@GetMapping(value="/r1")
@PreAuthorize("hasAnyAuthority('p1')")
public String r(){
return "访问资源1";
}
}