目录
1.spring security中用户登录做数据库或者远程调用
一:使用场景和考虑
在上一节,我们主要配置授权码和密码模式, 主要还是2个配置config。
一个是资源服务器的配置,包含了写死了的客户端,本地存储token以及访问约束安全配置。我们需要思考的问题:
(1)客户端能否在数据库中配置?
(2)access token存储放在本地内存,如果分布式部署不能共享怎么办?
第二个是spring security的配置,就一个用户授权码登录校验.。我们需要思考:
(1)用户配值又是写死在代理,如果放在数据库中怎样?(实际生产中用户密码等肯定是另一个服务中,这里怎么办?)
二:解决方案
我们从简单到难的依次解决:
1.spring security中用户登录做数据库或者远程调用
(1)自定义service实现UserDetailsService(关于一些注意,我写在代码的注释中了)
package springcloud.oauth2.service;
import java.util.ArrayList;
import org.springframework.security.core.userdetails.User;
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.crypto.factory.PasswordEncoderFactories;
import org.springframework.stereotype.Service;
/**
* 这里是用户登录验证使用
* @代码描述:
* @author monxz
*
* @time 2019年6月21日
*/
@Service
public class UserServiceDetail implements UserDetailsService {
//TODO:这里写死了,实际上就是从数据库中抓取,在实际生产中时候远程调用的,所以我写死了这里
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.err.println("编码123456后:"+PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("123456"));
User user=new User("admin",PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("admin"), true, true, true, true, new ArrayList<>());
return user;
}
}
(2)spring security的配置中就调用这个service来校验用户账户密码
package springcloud.oauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import springcloud.oauth2.service.UserServiceDetail;
/**
*
* @代码描述:spring security的配置
* @author monxz
*
* @time 2019年6月21日
*/
@EnableWebSecurity//开启权限验证
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserServiceDetail details;
/**
* 配置这个bean会在做AuthorizationServerConfigurer配置的时候使用
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
//
// /**
// * 配置用户
// * 使用内存中的用户,实际项目中,一般使用的是数据库保存用户,具体的实现类可以使用JdbcDaoImpl或者JdbcUserDetailsManager
// * @return
// */
// @Bean
// @Override
// protected UserDetailsService userDetailsService() {
// InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// manager.createUser(User.withUsername("admin").password(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("admin")).authorities("USER").build());
// return manager;
// }
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(details);
}
}
2.认证服务器中的-token access存储:
这里思考一个问题:在上述的方法中我们看到一旦第三方获取access token就一直可用。这样token一直有效,明显不科学。但
是每次都重新请求获取token,有特别消耗资源。如果设置token的失效时间合适,就可以在2个中平衡
(1)自定义token的存储方式(直接复制就可用)
package springcloud.oauth2.config.redis;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
@Slf4j
public class MyRedisTokenStore implements TokenStore {
private static final String ACCESS = "access:";
private static final String AUTH_TO_ACCESS = "auth_to_access:";
private static final String AUTH = "auth:";
private static final String REFR