随着公司资源,市场,以及深圳部分业务拓展,公司希望将公司所有的用户信息进行整合,搭建一个统一平台,用来支持各业务线的用户授权认证,方便其他子公司授权后获取资源系统的资源,最后经过讨论,决定采用Springsecurity+Oauth2.0+JWT来实现用户认证中心。
oauth2.0是一种授权机制,由第三方向资源所有者请求授权,资源所有者同意授权后,第三方去授权服务器获取令牌,资源服务器发放令牌,第三方使用令牌去访问资源服务器的资源。资源服务器校验token无误后开放资源。流程如下图所示
OAuth2.0一共包含四种授权模式:授权码,隐藏式,密码式,凭证式
关于这一部分内容可以参考阮一峰老师的:http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html 讲的非常的详细
在token方面,普通的token需要查库或者内存验证token 是否有效,而JWT不用查库或者少查库,直接在服务端进行校验,并且不用查库。因为用户的信息及加密信息在第二部分payload和第三部分签证中已经生成,只要在服务端进行校验就行,并且校验也是JWT自己实现的。而且第二部分payload可以拓展自己的业务信息,比如用户权限等。
具体实现:
/**
* OAuth2 配置文件
*
* @author yangle
* @date 2020-06-15 14:44
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Autowired
public PasswordEncoder passwordEncoder;
@Autowired
public UserService userService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
private TokenStore jwtTokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
//token存储方式
.tokenStore(jwtTokenStore)
//token转换方式使用jwt
.accessTokenConverter(jwtAccessTokenConverter)
//用户验证
.userDetailsService(userService)
//支持password模式
.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//定义客户端约束条件,这里采用数据库方式配置
JdbcClientDetailsServiceBuilder jdbc = clients.jdbc(dataSource);
//指定加密方式
jdbc.passwordEncoder(passwordEncoder);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//允许客户端访问 OAuth2.0 授权接口
security.allowFormAuthenticationForClients();
//允许已授权用户访问 checkToken 接口
security.checkTokenAccess("isAuthenticated()");
//允许已授权用户访问 获取 token 接口
security.tokenKeyAccess("isAuthenticated()");
}
}
AuthorizationServerConfigurer类继承AuthorizationServerConfigurerAdapter,重写里面三个configure方法。
/**
* spring security 基础配置
*
* @author yangle
* @date 2020-06-15 14:04
*/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").permitAll();
}
}
WebSecurityConfig类继承WebSecurityConfigurerAdapter,主要用于spring security 基础配置,关于这块详细的配置可以去学习下spring security,这里侧重点是为了用户认证,没有详细去写。
/**
* Jwt配置类
*
* @author yangle
* @date 2020-06-15 14:47
*/
@Configuration
public class JwtTokenConfig {
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("token");
return accessTokenConverter;
}
}
Jwt配置类,这里需要注意客服端签名应该与授权服务器签名一致
/**
* 实现 UserDetailsService
*
* @author yangle
* @date 2020-06-15 14:06
*/
@Component
public class UserService implements UserDetailsService {
private Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private UserInfoService userInfoService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username is:" + username);
UserInfo userInfo = userInfoService.getUserInfoByUsername(username);
if (userInfo == null) {
throw new UsernameNotFoundException("the user is not found");
}
List authorities = new ArrayList<>();
//此处可以根据自己的业务添加权限,这里就写死了
authorities.add(new SimpleGrantedAuthority("admin"));
return new org.springframework.security.core.userdetails.User(username, userInfo.getPassword(),
authorities);
}
}
UserService实现UserDetailsService,该类是实现Springsecurity用户身份验证的一种简单方式,结合 AuthenticationProvider
的方式可以自行去了解学习下Springsecurity。
以上是比较重要的代码,userInfoService这个类就不在这里说了,就是简单的去数据库进行查找。
github地址:https://github.com/jcyangl/Spring-Security-oauth2.0