前段时间有同学私信我,让我讲下Oauth2授权模式,并且还强调是零基础的那种,我也不太理解这个零基础到底是什么程度,但是我觉得任何阶段的同学看完我这个视频,对OAuth2的理解将会有很大的提升,并且也会熟练的使用SpringSecurity OAuth2,轻松搭建认证服务和资源服务。
Spring Security是一套安全框架,可以基于RBAC(基于角色的权限控制)对用户的访问权限进行控制,核心思想是通过一套filterChanin进行拦截和过滤
Oauth2是一个关于授权的官方标准,核心思路是通过各种认证手段(需要用户自己选择实现)进行认证用户身份,并颁发token,使得第三方应用可以使用该令牌在限定时间和限定范围内访问指定资源
Spring Security OAuth2建立在Spring Security的基础之上,实现了OAuth2的规范 概念部分铺垫完成了,现在我们讲下OAuth2的四种授权模式
为什么提供四种呢?四种授权模式代表OAuth授权第三方的不同互信程度
通过授权码获取token
当用户使用B网站的账号(如微信)授权登录A网站
简化模式在授权码模式的基础上减去了获取授权码的步骤,B网站认证通过之后,直接返回token 回调给A网站,所以又称为(授权码)“隐藏式”(implicit)
A网站要求用户直接输入用户名和密码,A网站自己拿着用户的密码和账号去B网站进行认证,直接获取token
客户端模式其实和用户就没关系了,其实也可以说它不属于Oauth了,因为是用网站A自己的身份信息去B网站认证获取token,A网站上的所有用户去访问B网站的资源,都是用的A网站自己的客户端信息。
这个一般用于微服务之间进行认证,如服务A想访问服务B,那么服务B需要校验服务A有没有权限访问自己,所以就需要校验服务B的token,这时就可以采用客户端模式,后面讲资源服务去认证中check_toekn的时候,用的就是这种方式。
现在四种授权模式讲完了,大家是不是有个疑问:前面三种授权方式,拿到token之后,是怎么和用户进行绑定的呢?接下来看下实战过程中,是怎么用SpringSecurity Oauth2 实现四种授权方式。
根据clientID获取客户端信息,security会去调用多次,所以一般加上缓存
package com.lglbc.oauth2.config.details.client;
import com.lglbc.oauth2.entity.OauthClient;
import com.lglbc.oauth2.enums.PasswordEncoderTypeEnum;
import com.lglbc.oauth2.service.OauthClientService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* @author: 乐哥聊编程(全平台同号)
*/
@Service
@RequiredArgsConstructor
public class ClientDetailsServiceImpl implements ClientDetailsService {
private final OauthClientService oauthClientService;
@Override
public ClientDetails loadClientByClientId(String clientId) {
// 获取client信息
OauthClient oauthClient = oauthClientService.lambdaQuery().eq(OauthClient::getClientId, clientId).one();
if (Objects.nonNull(oauthClient)) {
BaseClientDetails clientDetails = new BaseClientDetails(
oauthClient.getClientId(),
oauthClient.getResourceIds(),
oauthClient.getScope(),
oauthClient.getAuthorizedGrantTypes(),
oauthClient.getAuthorities(),
oauthClient.getWebServerRedirectUri());
clientDetails.setClientSecret(PasswordEncoderTypeEnum.NOOP.getPrefix() + oauthClient.getClientSecret());
clientDetails.setAccessTokenValiditySeconds(oauthClient.getAccessTokenValidity());
clientDetails.setRefreshTokenValiditySeconds(oauthClient.getRefreshTokenValidity());
return clientDetails;
} else {
throw new NoSuchClientException("没找到客户端信息");
}
}
}
package com.lglbc.oauth2.config.details.user;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* @author: 乐哥聊编程(全平台同号)
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SysUserDetails implements UserDetails {
/**
* 扩展字段
*/
private Long userId;
/**
* 默认字段
*/
private String username;
private String password;
private Boolean enabled;
private Collection<SimpleGrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return this.enabled;
}
}
package com.lglbc.oauth2.config.details.user;
import com.lglbc.oauth2.entity.Role;
import com.lglbc.oauth2.entity.User;
import com.lglbc.oauth2.enums.PasswordEncoderTypeEnum;
import com.lglbc.oauth2.mapper.UserRoleMapper;
import com.lglbc.oauth2.service.RoleService;
import com.lglbc.oauth2.service.UserService;
import com.xiaoleilu.hutool.collection.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class SysUserDetailServiceImpl implements UserDetailsService {
@Autowired
private UserService userServiceImpl;
@Autowired
private RoleService roleServiceImpl;
@Autowired
private UserRoleMapper userRoleMapper;
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
Map<String, Object> map = new HashMap<>();
map.put("username", name);
User user = userServiceImpl.lambdaQuery().eq(User::getUsername, name).one();
if (user == null) {
throw new UsernameNotFoundException("此用户不存在");
}
Collection<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
List<String> roleIds = userRoleMapper.getRoleIdByUserId(user.getId());
if (CollectionUtil.isNotEmpty(roleIds)){
List<Role> roles = roleServiceImpl.lambdaQuery().in(Role::getId, roleIds).list();
List<String> roleCodes = roles.stream().map(Role::getCode).collect(Collectors.toList());
for (String roleCOde : roleCodes) {
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+roleCOde);
grantedAuthorities.add(grantedAuthority);
}
}
return new SysUserDetails(user.getId(), user.getUsername(),PasswordEncoderTypeEnum.BCRYPT.getPrefix() + user.getPassword(),true, grantedAuthorities);
}
}
package com.lglbc.oauth2.config;
import com.lglbc.oauth2.config.details.client.ClientDetailsServiceImpl;
import com.lglbc.oauth2.config.details.user.SysUserDetails;
import com.xiaoleilu.hutool.collection.CollectionUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
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.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import java.security.KeyPair;
import java.util.*;
/**
* @author: 乐哥聊编程(全平台同号)
*/
@Configuration
@EnableAuthorizationServer
@RequiredArgsConstructor
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final ClientDetailsServiceImpl clientDetailsService;
// 该对象用来将令牌信息存储到Redis中
private final RedisConnectionFactory redisConnectionFactory;
/**
* OAuth2客户端
*/
@Override
@SneakyThrows
public void configure(ClientDetailsServiceConfigurer clients) {
clients.withClientDetails(clientDetailsService);
}
/**
* 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
// Token增强
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
tokenEnhancers.add(tokenEnhancer());
tokenEnhancers.add(jwtAccessTokenConverter());
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
// 获取原有默认授权模式(授权码模式、密码模式、客户端模式、简化模式)的授权者
List<TokenGranter> granterList = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granterList);
endpoints
.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter())
.tokenEnhancer(tokenEnhancerChain)
.tokenGranter(compositeTokenGranter)
.tokenServices(tokenServices(endpoints))
;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("permitAll()");
}
public DefaultTokenServices tokenServices(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
tokenEnhancers.add(tokenEnhancer());
tokenEnhancers.add(jwtAccessTokenConverter());
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setReuseRefreshToken(true);
tokenServices.setClientDetailsService(clientDetailsService);
tokenServices.setTokenEnhancer(tokenEnhancerChain);
return tokenServices;
}
/**
* JWT内容增强
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
Map<String, Object> additionalInfo = CollectionUtil.newHashMap();
if (Objects.nonNull(authentication.getUserAuthentication())) {
Object principal = authentication.getUserAuthentication().getPrincipal();
if (principal instanceof SysUserDetails) {
SysUserDetails sysUserDetails = (SysUserDetails) principal;
additionalInfo.put("userId", sysUserDetails.getUserId());
additionalInfo.put("username", sysUserDetails.getUsername());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
}
}
return accessToken;
};
}
/**
* 使用非对称加密算法对token签名
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyPair());
return converter;
}
/**
* 密钥库中获取密钥对(公钥+私钥)
*/
@Bean
public KeyPair keyPair() {
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray());
KeyPair keyPair = factory.getKeyPair("jwt", "123456".toCharArray());
return keyPair;
}
}
package com.lglbc.oauth2.config;
import com.lglbc.oauth2.common.result.R;
import com.lglbc.oauth2.common.result.ResultCode;
import com.xiaoleilu.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
/**
* @author: 乐哥聊编程(全平台同号)
*/
@Configuration
@EnableWebSecurity
@Slf4j
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService sysUserDetailsService;
private final String realName = ".";
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/oauth/**", "/test/**", "/login").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic().and()
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
}
/**
* 认证管理对象
*
* @return
* @throws Exception
*/
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 添加自定义认证器
*
* @param auth
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
/**
* 设置默认的用户名密码认证授权提供者
*
* @return
*/
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(sysUserDetailsService);
provider.setPasswordEncoder(passwordEncoder());
provider.setHideUserNotFoundExceptions(false); // 是否隐藏用户不存在异常,默认:true-隐藏;false-抛出异常;
return provider;
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
/**
* 自定义认证异常响应数据
*/
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return (request, response, e) -> {
if (e.getMessage().equals("User must be authenticated with Spring Security before authorization can be completed.")) {
response.addHeader("WWW-Authenticate", "Basic realm= " + realName);
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
} else {
response.setStatus(HttpStatus.OK.value());
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Cache-Control", "no-cache");
R result = R.failed(ResultCode.CLIENT_AUTHENTICATION_FAILED);
response.getWriter().print(JSONUtil.toJsonStr(result));
response.getWriter().flush();
}
};
}
}
package com.lglbc.oauth2;
import com.lglbc.oauth2.common.result.R;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;
import java.security.KeyPair;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
/**
* @author: 乐哥聊编程(全平台同号)
*/
@RestController
@RequestMapping("/oauth")
@AllArgsConstructor
@Slf4j
public class AuthController {
private KeyPair keyPair;
private final TokenEndpoint tokenEndpoint;
@PostMapping("/token")
public Object postAccessToken(
Principal principal,
@RequestParam Map<String, String> parameters
) throws HttpRequestMethodNotSupportedException {
OAuth2AccessToken accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
return R.ok(accessToken);
}
@GetMapping("/public-key")
public Map<String, Object> getPublicKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
在这里插入图片描述
curl --location --request POST --X POST 'http://localhost:8080/oauth/token?code=k9jcxv&grant_type=authorization_code' \
--header 'User-Agent: Apipost client Runtime/+https://www.apipost.cn/' \
--header 'Authorization: Basic YWRtaW46YW1z'
curl --location --request POST --X POST 'http://localhost:8080/oauth/token?refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhbXMiLCJzY29wZSI6WyJ3cml0ZSJdLCJhdGkiOiI4NjZmYWY2MC05MTE1LTQ0NGMtOWNkNi05MjRmYTRlZjQ4YjUiLCJleHAiOjE2NTQ1MzExMzcsInVzZXJJZCI6NCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiIyNDg1M2NiNi02ZGM1LTRlMDQtYjAxOC0wMGE0MGMxNGMyNjAiLCJjbGllbnRfaWQiOiJhZG1pbiIsInVzZXJuYW1lIjoiYW1zIn0.BX87xbC1SEVgXsQ6qdI1_RLVOY1ffqoKDvd-Fnu5FfJor6CR-3NtUjMBIQig_jAnJwptG8ZIs1q715GAQTtgoRVUMsnXBv8RKmlDvxjclUYIWrRXy1d9Rj84WC4niDU8rOzazr4L1-chkwod3rAEDAZSiBcd4XZ1S2cfG7WBSH1TcivNtY0pk_ePS08ItN_2wYm57-7_JD8XCRecpn6nF6ax20ysimqPftAKIiVzvhhN4O_TsHd3-lB7ZYTsT-SlzjBu43gm5eGFWhsOBK7NgxObwoeXaoARrzW3GaUw8DsLTKsDofyIIFGnKee9sooAwejPrsxtVRJlfj8gIc5EdA&grant_type=refresh_token' \
--header 'User-Agent: Apipost client Runtime/+https://www.apipost.cn/' \
--header 'Authorization: Basic YWRtaW46YW1z'
curl --location --request POST --X POST 'http://localhost:8080/oauth/token?grant_type=password&username=ams&password=ams' \
--header 'User-Agent: Apipost client Runtime/+https://www.apipost.cn/' \
--header 'Authorization: Basic YWRtaW46YW1z'
curl --location --request POST --X POST 'http://127.0.0.1:8080/oauth/token?grant_type=client_credentials' \
--header 'User-Agent: Apipost client Runtime/+https://www.apipost.cn/' \
--header 'Authorization: Basic YWRtaW46YW1z'
package com.lglbc.oauth2.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lglbc.oauth2.common.KeyPairUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.codec.Base64;
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.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.client.RestTemplate;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
import java.util.stream.Collectors;
@Configuration
public class Oauth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String CHECK_TOKEN_URL = "http://localhost:8080/oauth/check_token";
// 也可以使用认证服务去校验
// @Override
// public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
// RemoteTokenServices tokenService = new RemoteTokenServices();
// tokenService.setCheckTokenEndpointUrl(CHECK_TOKEN_URL);
// tokenService.setClientId("resource");
// tokenService.setClientSecret("resource");
// resources.tokenServices(tokenService);
// }
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//设置用于解码的非对称加密的公钥
converter.setVerifierKey(KeyPairUtil.getPubKey());
return converter;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 任何请求都必须具有all这个域的授权
.antMatchers("/test/read").access("#oauth2.hasScope('read') || #oauth2.hasScope('write')")
.antMatchers("/test/write").access("#oauth2.hasScope('write')")
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
package com.lglbc.oauth2.config;
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;
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/test/**").authenticated();
// 禁用CSRF
http.csrf().disable();
}
}
定义两个接口
@RequestMapping("/read")
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public String read(){
System.out.println("read");
return "read";
}
@RequestMapping("/write")
// @Secured({"ROLE_ADMIN"})
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public String write() throws ParseException {
return UserContextUtil.getUserId()+""+UserContextUtil.getUserName();
}
@PreAuthorize("hasAuthority('ADMIN2')")
@PreAuthorize("hasRole('ADMIN')") //允许
@PreAuthorize("hasRole('ROLE_ADMIN')") //允许
@PreAuthorize("hasAuthority('ROLE_ADMIN')") //允许
持续整理...
源码部分
由于在资源服务中,我们没有重写userDetailService,所以我们是获取不到用户的信息(我们也没必要写),但是我们可以自己解析token,拿到用户信息
package com.lglbc.oauth2.config;
import com.lglbc.oauth2.common.UserContextUtil;
import com.nimbusds.jose.JWSObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String authorization = request.getHeader("Authorization");
if (StringUtils.isBlank(authorization)) {
return true;
}
String token = StringUtils.substringAfter(authorization, "Bearer ");
if (StringUtils.isBlank(token)) {
return true;
}
try {
Map<String, Object> stringObjectMap = JWSObject.parse(token).getPayload().toJSONObject();
UserContextUtil.setUser(stringObjectMap);
} catch (Exception e) {
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserContextUtil.removeUser();
}
}
成长心路 | 优质书单 | 面试资料
牛人故事 | 前沿技术 | 视频教程