鉴权(中篇)
SpringSecurity + OAuth2 + JWT
前言
文章我们完成了SpringSecurity+OAuth2.0的整合,中篇我们利用上篇完成的代码。
开始整合JWT。
1、前期准备
1.1、核心依赖
<!--JWT所需依赖-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.0.10.RELEASE</version>
</dependency>
<!--SpringSecurity关于数据的一些核心类-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
</dependency>
1.2、User
我们需要自定义一个用户类
@Data
public class FastCloudUser implements Serializable {
private static final long serialVersionUID = 4989309292401711788L;
private Long id;
private String username;
private String password;
@Transient
private Set<GrantedAuthority> authorities = new HashSet<>();
public FastCloudUser() {
this.username = "user";
this.password = "12345678";
}
public Set<GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> userAuthotities = new HashSet<>();
userAuthotities.add(new SimpleGrantedAuthority("管理员(Admin)"));
return userAuthotities;
}
}
GrantedAuthority
是SpringSecurity中用于用户角色等相关权限的类
1.3、UserDetailsService
我们需要一个从数据库读取用户信息的方法,这里我们需要创建一个类FastCloudUserDetailsService
实现系统给我们提供的,UserDetailsService
接口,代码如下
@Slf4j
public class FastCloudUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
// 这里的username 可以是username、mobile、email
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("表单登录用户名:" + username);
return buildUser(username);
}
private UserDetails buildUser(String userId) {
// 根据用户名查找用户信息
//根据查找到的用户信息判断用户是否被冻结
//TODO
log.info("数据库密码是:" + "");
FastCloudUser mermaidUser = new FastCloudUser();
return new User(mermaidUser.getUsername(),passwordEncoder.encode(mermaidUser.getPassword()),mermaidUser.getAuthorities());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
1.4、TokenEnhancer
token相关的转换类
@Slf4j
public class FastCloudTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
log.info(":>>> MermaidTokenEnhancer enhance ");
Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("userId", 1001L);
additionalInfo.put("roles", "admin");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
log.debug(":>>> MermaidTokenEnhancer {$accessToken}:{}", accessToken);
return accessToken;
}
}
我们在该类中还创建了PasswordEncoder
类,用来做密码的加密功能,在此处我们并没有真实的从数据库进行用户数据的查询比对密码操作,后续的数据库相关操作,可以将代码写在TODO
处。
2、操作步骤
2.1、AuthorizationServerConfigurerAdapter
我们通过继承该类实现了AuthServerConfiguration
自定义的功能,这里我们继续完成,代码如下
@Slf4j
@Configuration
@EnableAuthorizationServer
public class AuthServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserDetailsService userDetailsService;
/**
* Redis操作
* @return
*/
@Bean
public RedisTokenStore tokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
/**
* 客户端验证
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client_id")
.scopes("all")
.secret(passwordEncoder.encode("123456"))
.authorizedGrantTypes("implicit","password", "refresh_token","client_credentials").autoApprove(true);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenStore(tokenStore()).accessTokenConverter(jwtAccessTokenConverter()).tokenEnhancer(tokenEnhancerChain());
}
@Bean
public TokenEnhancerChain tokenEnhancerChain() {
log.info(":>>> tokenEnhancerChain with");
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Lists.newArrayList(new FastCloudTokenEnhancer(), jwtAccessTokenConverter()));
return tokenEnhancerChain;
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
log.info(":>>> jwtAccessTokenConverter with {$converter}:{}", converter.toString());
return converter;
}
}
2.2、ResourceServerConfig
我们在上一篇的基础之上,改为资源控制,并开放一些获取鉴权资源的接口
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
/**
* 资源控制
* @param http
* @throws Exception
*/
@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/**","/oauth2/**","/open-api/v1/uaa/oauth2/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
2.3、SecurityConfiguration
我们将上一篇固定的授权资源,改为如下
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected UserDetailsService userDetailsService(){
return new FastCloudUserDetailsService();
}
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
// return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
protected 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().authenticated()
.and()
.httpBasic().disable();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager manager = super.authenticationManagerBean();
return manager;
}
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
}
至此完成代码。接下来我们进行测试
3、测试
我们利用Postman分别测试4种模式。
3.1、password模式
访问http://localhost:8081/oauth/token,填写内容,如下图。
各位大佬们关注下公众号呗,后续很多内容持续更新
关于我
email : liangliang1259@163.com
更多请关注公众号程序员阿亮
:
点击下图
https://img.haomeiwen.com/i838913/c904dbc84e2a1c98.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240
网友评论