Oauth2配置
在对Oauth2配置之前需要先熟悉三个适配器
- WebSecurityConfigurerAdapter
- AuthorizationServerConfigurerAdapter
- ResourceServerConfigurerAdapter
说一下以上三个适配器的区别
WebSecurityConfigurerAdapter是在spring-security-config包下的,AuthorizationServerConfigurerAdapter和ResourceServerConfigurerAdapter是在spring-security-oauth包下的,这样WebSecurityConfigurerAdapter适配器就与另外两个有了本质的区别。WebSecurityConfigurerAdapter是对当前项目的http配置,ResourceServerConfigurerAdapter是对oauth2的http配置,且WebSecurityConfigurerAdapter执行顺序要优先于ResourceServerConfigurerAdapter。AuthorizationServerConfigurerAdapter主要是对token认证的配置。
WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter是对当前系统进行鉴权,包含且不仅限于跨域,表单提交,session处理等。
是Spring Security的标准配置入口。在 此项目中,主要用来配置 PasswordEncoder、用户自定义查询和HttpSecurity安全规则。
在com.shareprog.auth.configuration.security包下创建自定义适配器,代码如下:
package com.shareprog.auth.configuration.security;
import java.util.Arrays;
import java.util.Collections;
import org.springframework.beans.factory.annotation.Autowired;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(WebSecurity web) throws Exception {
// 允许静态资源访问,可以在这里写单点登录页面,未使用
web.ignoring().antMatchers("templates/**");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/user","/oauth/logout").permitAll()
.anyRequest().authenticated()
//登录时会传一个csrf进行验证,如果没有则不会进行跳转,所以在这里需要关掉该功能
.and()
.csrf().disable() //禁用csrf
.cors()
.and()
.httpBasic()
;
}
/**
* 解决Cors跨域问题
* @return
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
// 预检请求的有效期,单位为秒
configuration.setMaxAge(3600L);
//允许跨域访问的域名
configuration.setAllowedOrigins(Collections.singletonList("*"));
//允许的请求方法
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "HEAD", "DELETE", "PATCH", "PUT", "OPTION"));
// 是否发送cookie信息
configuration.setAllowCredentials(false);
//允许的请求头
configuration.setAllowedHeaders(Collections.singletonList("*"));
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
configuration.addExposedHeader("Authorization");
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
/**
* 加密方式
* <p>Title: passwordEncoder</p>
* <p>Description: </p>
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 认证管理对象
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
上面所有的方法中,还必须自定义实现UserService 的用户查询方法(loadUserByUsername),在此之前,需要先创建一个用户表。为了减少代码开发量,可以看到loadUserByUsername方法返回的是UserDetails类,该类spring-security-core已经提供了一个User实现类(org.springframework.security.core.userdetails.User),该类属性如下:
public class User implements UserDetails, CredentialsContainer {
// 用户密码
private String password;
// 用户名
private final String username;
// 权限集合
private final Set<GrantedAuthority> authorities;
// 账户是否未过期
private final boolean accountNonExpired;
// 账户是否解锁
private final boolean accountNonLocked;
// 账户(凭据)密码是否未过期
private final boolean credentialsNonExpired;
// 账户是否已启用
private final boolean enabled;
...
}
一般来说,我们对用户只有是否禁用/启用,这个时候账户过期,解锁,密码过期都是不用的,但是boolean默认值是false。这几个值要么通过数据库反序列化赋值,要么使用一个子类继承重写get方法,这里为了方便,直接通过User提供的建造者模式直接返回一个新的对象。
首先在pom.xml文件中添加JDBC依赖:
<!-- jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
application.yml文件中也需要加入数据库配置,加入后结果如下:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/shareprog?userUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
security:
user:
name: auth
password: auth
这时候必须现有一个用户表,数据库Mysql表DDL如下:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `users` (
`username` varchar(64) NOT NULL COMMENT '用户名',
`password` varchar(255) NOT NULL COMMENT '密码',
`enabled` tinyint(1) DEFAULT '1' COMMENT '是否启用',
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Compact;
ALTER TABLE users ADD UNIQUE (username);
关于表的设计可以参考UserDetailsService的实现类:org.springframework.security.provisioning.JdbcUserDetailsManager,内含大量的对users表和groups表的增删改查。在通常的OA系统中,groups代表的应该是部门。在此我们使用自定义的用户-角色-权限:
以下DDL仅供参考使用:
DROP TABLE IF EXISTS `users_roles`;
CREATE TABLE `users_roles` (
`username` varchar(64) NOT NULL COMMENT '用户名',
`role` varchar(64) NOT NULL COMMENT '角色',
PRIMARY KEY (`username`,`role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和角色关联表';
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
`role` varchar(64) NOT NULL COMMENT '角色',
`role_name` varchar(255) NOT NULL COMMENT '角色名称',
PRIMARY KEY (`role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
DROP TABLE IF EXISTS `roles_authorities`;
CREATE TABLE `roles_authorities` (
`role` varchar(64) NOT NULL COMMENT '角色',
`authority` int(64) NOT NULL COMMENT '权限',
PRIMARY KEY (`role`,`authority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限表';
DROP TABLE IF EXISTS `authorities`;
CREATE TABLE `authorities` (
`authority` varchar(64) NOT NULL COMMENT '权限',
`authority_name` varchar(255) NOT NULL COMMENT '权限名称',
PRIMARY KEY (`authority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';
DROP TABLE IF EXISTS `users_authorities`;
CREATE TABLE `users_authorities` (
`username` varchar(128) NOT NULL COMMENT '用户名',
`authority` varchar(128) NOT NULL COMMENT '权限',
PRIMARY KEY (`username`, `authority`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '用户权限表';
在com.shareprog.auth.service包下创建自定义用户权限查询,代码如下:
package com.shareprog.auth.service;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor;
/**
* @Title 自定义权限用户查询
* @author cl
* @date 2019年12月11日 下午5:32:23
* @version 1.0
*/
@Service
@AllArgsConstructor
public class CustomUserService implements UserDetailsService {
private static final String FIND_BY_USEENAME_STATEMENT = "SELECT username, password, enabled FROM user WHERE username = ?";
private static final String LIST_ALL_AUTHORITY_STATEMENT = "SELECT `authority` FROM authorities";
private static final String LIST_AUTHORITY_BY_USER_STATEMENT = "SELECT au.`authority` FROM users u"
+ " left join users_roles ur on u.username = ur.username "
+ " left join roles r on r.role = ur.role"
+ " left join roles_authorities ra on ra.role = r.role"
+ " left join authorities au on au.authority = ra.authority";
private final JdbcTemplate jdbcTemplate;
@Override
public UserDetails loadUserByUsername(String username) {
Map<String, Object> userMap = jdbcTemplate.queryForMap(FIND_BY_USEENAME_STATEMENT, username);
List<String> authorities;
if ("admin".equals(username)) {
authorities = jdbcTemplate.queryForList(LIST_ALL_AUTHORITY_STATEMENT, String.class);
} else {
authorities = jdbcTemplate.queryForList(LIST_AUTHORITY_BY_USER_STATEMENT, String.class, username);
}
authorities.add("isLogin");
return User.builder()
.username((String) userMap.get("username"))
.password((String) userMap.get("password"))
.disabled(!(boolean)userMap.get("enabled"))
.authorities(authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()))
.build();
}
}
ResourceServerConfigurerAdapter
这是资源服务器配置,主要是基于oauth2对http安全配置和资源安全配置相关。
资源服务器的职责是对来自OAuth客户端的access_token进行鉴权。一个资源服务器包含多个接口,一部分接口作为资源服务器的资源提供给OAuth的客户端访问,另一部分接口不由资源服务器管理。由资源服务器管理的接口安全性配置在此类中,其余接口的安全性配置在WebSecurityConfig类中。当请求中包含Oauth2的access_token时,Spring Security会根据资源服务器配置进行过滤。EnableResourceServer会创建一个WebSecurityConfigurerAdapter,执行顺序(Order)是3。在WebSecurityConfig之前运行,优先级更高。
ResourceServerConfigurerAdapter提供了以下两方面的自定义配置。
- HttpSecurity:Spring Security的安全配置类,注意此处配置的URL与过滤器映射关系的优先级 要高于SecurityConfiguration类。
- ResourceServerSecurityConfigurer:配置ResourceServerTokenServices、resourceId等。
ResourceServerTokenServices的配置很关键。OAuth的资源服务器主要负责对传递进来的access_token 进行验证,验证通过后才允许 OAuth 客户端访问资源端点。在实际应用中,由于授权服 务器和资源服务器的系统架构不同,所以具体的验证方式也不同,常用的验证方式有以下三种。
- 当授权服务器与资源服务器在同一个应用中时,使用默认的DefaultTokenServices在服务器内部进行验证。
- 当授权服务器和资源服务器是分离的两个应用,且access_token类型为Opaque时,使用RemoteTokenServices资源服务器远程调用授权服务器进行验证。
- 当授权服务器和资源服务器是分离的两个应用,且access_token类型为JWT时,一般使用DefaultTokenServices 资源服务器远程调用授权服务器进行验证。注意,需要将DefaultTokenServices的tokenStore属性设置为JwtTokenStore。
另外,需要配置属性resourceId为“sso-resource”,代替默认值“oauth2-resource”。
package com.shareprog.auth.configuration.security;
import javax.servlet.http.HttpServletResponse;
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;
@EnableResourceServer
@Configuration
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "sso-resource";
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.anyRequest().permitAll()
.and()
.httpBasic();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID)
//.stateless(false)
;
}
}
AuthorizationServerConfigurerAdapter
授权服务器配置
package com.shareprog.auth.configuration.security;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
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.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import com.shareprog.auth.configuration.security.authentication.CustomUserAuthenticationConverter;
import com.shareprog.auth.configuration.security.handler.CustomWebResponseExceptionTranslator;
import com.shareprog.auth.configuration.security.service.CustomJdbcClientDetailsService;
import lombok.RequiredArgsConstructor;
@EnableAuthorizationServer
@Configuration
@RequiredArgsConstructor
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final DataSource dataSource;
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final RedisConnectionFactory connectionFactory;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()");//设置为isAuthenticated()则校验token需要认证
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
DefaultAccessTokenConverter defaultAccessTokenConverter=new DefaultAccessTokenConverter();
defaultAccessTokenConverter.setUserTokenConverter(new CustomUserAuthenticationConverter());
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenStore(jdbcTokenStore())
.accessTokenConverter(defaultAccessTokenConverter)
.exceptionTranslator(new CustomWebResponseExceptionTranslator())
;
}
public TokenStore redisTokenStore() {
return new RedisTokenStore(connectionFactory);
}
public JdbcTokenStore jdbcTokenStore() {
return new JdbcTokenStore(dataSource);
}
private ClientDetailsService clientDetailsService() {
return new CustomJdbcClientDetailsService(dataSource);
}
@Bean
public TokenEnhancer accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// 配置自定义转换器
DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
tokenConverter.setUserTokenConverter(new CustomUserAuthenticationConverter());
converter.setAccessTokenConverter(tokenConverter);
return converter;
}
}
授权服务器主要是对token进行配置
AuthorizationServerSecurityConfigurer主要配置授权服务器的安全,主要就是运行所有token校验接口是可以访问的。ClientDetailsServiceConfigurer主要配置授权服务器的客户端clients信息。一般来说可以通过inMemory方式设置client信息,百度上大部分初始教程都是以此种方式的。如果想要做动态配置的话,最好是使用数据库配置,可以使用非关系型数据库redis或者关系型数据库MySQL。
如果使用redis,需要在pom.xml文件添加redis依赖:
<!-- redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
这里使用MySQL作为示例。
package com.shareprog.auth.configuration.security.service;
import javax.sql.DataSource;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
/**
* @ClassName: CustomJdbcClientDetailsService
* @Description: 自定义客户端信息表,可以在构造函数中使用
* setSelectClientDetailsSql方法重写查询sql语句
* @author cl
* @date 2021年1月19日
*/
public class CustomJdbcClientDetailsService extends JdbcClientDetailsService {
public CustomJdbcClientDetailsService(DataSource dataSource) {
super(dataSource);
}
}
这里并没有进行任何操作,只是继承了JdbcClientDetailsService的方法,事实上直接使用JdbcClientDetailsService也是可以的。但是一般而言,我们需要自定义一些数据库数据之类的操作,这里为了方便,创建的数据库和JdbcClientDetailsService提供DML保持一致,所以不需要进行任何重写。
DDL如下:
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(64) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '客户端ID',
`client_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '客户端名称',
`client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户端密匙',
`resource_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '资源id集合',
`web_server_redirect_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '重定向URL',
`scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '权限范围,可选值包括read,write',
`authorized_grant_types` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '可选值包括authorization_code,password,refresh_token,implicit,client_credentials',
`authorities` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '指定客户端所拥有的Spring Security的权限值',
`access_token_validity` int(11) NULL DEFAULT 43200 COMMENT 'token的有效时间值',
`refresh_token_validity` int(11) NULL DEFAULT 2592000 COMMENT 'refresh_token的有效时间值',
`additional_information` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
`autoapprove` tinyint(1) NULL DEFAULT 1 COMMENT '是否信任',
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Table structure for oauth_access_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`token_id` varchar(255) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(255) DEFAULT NULL,
`user_name` varchar(255) DEFAULT NULL,
`client_id` varchar(255) DEFAULT NULL,
`authentication` blob,
`refresh_token` varchar(255) DEFAULT NULL,
UNIQUE KEY `authentication_id_index` (`authentication_id`) USING BTREE,
KEY `token_id_index` (`token_id`),
KEY `user_name_index` (`user_name`),
KEY `client_id_index` (`client_id`),
KEY `refresh_token_index` (`refresh_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for oauth_refresh_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`token_id` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`token` blob,
`authentication` blob,
KEY `token_id_index` (`token_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
事实上,我们使用oauth2的配置,返回的结果是固定的,有时候我们可能需要通过token需要获取用户的信息,例如昵称、性别、年龄之类的,所以我们还需要自定义返回结果,这里自定义返回一个display_name参数。
这里对使用lang3的工具类进行空的判定,加入依赖:
<!--lang3工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
package com.shareprog.auth.configuration.security.authentication;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
/**
* @ClassName: CustomUserAuthenticationConverter
* @Description: 自定义用户信息返回结果
* @author cl
* @date 2021年1月19日
*/
public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
@Override
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> response = new LinkedHashMap<>();
response.put(USERNAME, authentication.getName());
Object principal = authentication.getPrincipal();
if (principal instanceof User) {
User user = (User) principal;
if (StringUtils.isNotEmpty(user.getUsername())) {
response.put("display_name", user.getUsername());
}
}
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return response;
}
}
有时候在oauth2中,我们需要自定义认证失败返回的错误码,例如400,401,402等待,代码如下:
package com.shareprog.auth.configuration.security.handler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import lombok.extern.slf4j.Slf4j;
/**
* 自定义错误信息响应结果
*
* @author cl
*/
@Slf4j
public class CustomWebResponseExceptionTranslator implements WebResponseExceptionTranslator<OAuth2Exception> {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
log.error("响应错误信息:", e);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}