微服务登录问题:
解决方式:
我们使用客户端Token+oauth2+jwt+springsecurity
oauth2:简易,开放,安全,不接触账号密码
oauth2四种模式:
- 授权码模式
- 简化模式:没有授权码,直接token,安全性降低
- 密码模式:一般在自己系统中用(不接触三方)
- 客户端模式:不要用户名密码,直接返回token,在自己的服务器中使用,比如认证服务访问资源模式,你来访问我就直接返回token
- 实现
- 建立几个微服务
- 1导包
- 2搭建eureka,配置yml 注册eureka
- 3搭建zuul 配置zuul
- 4搭建resource 注册到eureka,开启zuul
- 5搭建auth,注册到eureka,开启zuul
- 6集成auth2
- 导包
- 7auth集成mybatis
- 导入数据库到hrm-auth
- 自定义UserDetailService
- 根据name查询用户 基本判断用户
- 查询所拥有的权限
- 把用户和权限封装成一个UserDetailService
- 把用户转成user 传参 用户名 密码 权限
- 权限装成他所需要的集合
- 返回一个UserDetailService
@Component
public class MyUserDetailService implements UserDetailsService {
@Autowired
private MyUserMapper myUserMapper;
@Autowired
private PermissionMapper permissionMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//通过username查询
MyUser myUser = myUserMapper.loadByUsername(username);
if(myUser==null){
System.out.println(username + "用户不存在");
}
//通过用户查询所拥有的权限
List<Permission> permissions = permissionMapper.loadByMyUserId(myUser.getId());
List<SimpleGrantedAuthority> authorities=new ArrayList<>();
permissions.forEach(permission -> {
authorities.add(new SimpleGrantedAuthority(permission.getExpression()));
});
//转成需要的数组
//参数需要 String username, String password, Collection<? extends GrantedAuthority> authorities
User user=new User(myUser.getUsername(),myUser.getPassword(),authorities);
return user;
}
}
- 配置springsecurity
- 1继承websecurityConfigureAdapter
- 2配置
- 3开启springsecurity
- 4密码匹配器
- 5重写configure方法
/**
* 对security安全配置
*/
@Configuration//相当于在xml 里面配置了bean
@EnableWebSecurity(debug = false)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean //密码模式用到
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
//配置认证管理器,授权模式为“poassword”时会用到
//配置服务详情
@Bean
public ClientDetailsService clientDetailsService(){
return new InMemoryClientDetailsService();
}
//配置一个编码器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//配置规则
@Override
public void configure(HttpSecurity http ) throws Exception {
http.csrf().disable()//屏蔽跨域处理
.authorizeRequests()//对请求做处理
.antMatchers("/login").permitAll()//对登录放行
.anyRequest().authenticated()//其他页面都要拦截
.and().formLogin()//允许进行表单登录
.successForwardUrl("/loginSuccess")//登录成功跳转
.and().logout().permitAll();//登出放行
}
}
- 配置auth2 认证服务配置
- 授权服务配置
- 集成AuthorizationServer。。。
- 开启服务授权配置
- 复写三个方法
- 一:基于内存客户端详情配置:创建了一个客户端详情类
- 1配置客户端id
- 2客户端密钥(注入密码匹配器给密钥加密)
- 3资源id (颁发的令牌只能通过资源id访问对应的资源)
- 4授权模式 客户端支持的授权模式
- 5允许的授权范围
- 6autoApprove(false)//是否自动授权
- 7回调url
- 二、授权服务端点配置(授权码和令牌管理)
- 在security配置中配置认证管理器(父类返回一个认证管理器)
- 1配置认证管理器
- 先配置令牌服务bean
- .配置令牌服务
- 创建默认的令牌服务
- 指定客户端详情配置
- 2令牌服务配置
- 配置一个bean基于内存的授权码配置
- 3授权码配置
- 4允许使用post发送请求
- 三:授权服务安全配置
- 放行检查token
- 允许使用表单提交代码
- 测试 然后测试密码模式
package cn.itsource.wyj.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration
@EnableAuthorizationServer
public class ClientDetailsServiceConfig extends AuthorizationServerConfigurerAdapter {
//一、配置客户端的参数
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//添加客户信息
clients.inMemory() //http://localhost:4000/oauth/authorize?client_id=www&response_type=code&redirect_uri=http://www.baidu.com
.withClient("www")//添加客户端id
.secret(passwordEncoder.encode("wyj"))//添加客户端密钥 加密
.resourceIds("itsource")//添加资源id
.authorizedGrantTypes("client_credentials",
"password","authorization_code","refresh_token")//允许授权类型
.scopes("emp")//允许授权类型 为emp
.autoApprove(false)//否需要跳转到授权页面让用户确认如果为true回直接发令牌
.redirectUris("http://www.baidu.com");
}
@Bean //建token存储在内存中
public TokenStore tokenStore(){
return new InMemoryTokenStore();
}
//配置令牌
@Autowired
private ClientDetailsService clientDetailsService;
public AuthorizationServerTokenServices tokenService(){
//设置默认的令牌服务
DefaultTokenServices defaultTokenServices=new DefaultTokenServices();
//指定客户端详情配置
defaultTokenServices.setClientDetailsService(clientDetailsService);
//支持刷新token
defaultTokenServices.setSupportRefreshToken(true);
//token存储方式
defaultTokenServices.setTokenStore(tokenStore());
//token有效时间
defaultTokenServices.setAccessTokenValiditySeconds(43200);//秒为单位
//刷新默认有效时间
defaultTokenServices.setRefreshTokenValiditySeconds(14400);
return defaultTokenServices;
}
//配置令牌访问端点
@Autowired
private AuthenticationManager authenticationManager;
@Bean//授权服务的bean
public AuthorizationCodeServices authorizationCodeServices(){
//基于内存存储的授权码服务
return new InMemoryAuthorizationCodeServices();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)//配置认证管理器
.authorizationCodeServices(authorizationCodeServices())//授权服务
.tokenServices(tokenService())//配置令牌管理服务
.allowedTokenEndpointRequestMethods(HttpMethod.POST);//允许post请求
super.configure(endpoints);
}
//授权服务安全配置
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permiAll()")//放行检查token
.checkTokenAccess("permiAll")//放行token检查
.allowFormAuthenticationForClients();//允许客户端进行表单身份验证,使用表单认证申请令牌
}
}
- 四:配置资源
- 1导包
- 2建类继承Res。。
- 开启资源服务配置
-3 配置资源id - 4复写2个方法 //
- 方法一:资源服务配置
- 5配置bena-》token远程验证效验配置
- 验证token
- 5方法二:web安全配置
- 判断授权范围
使用方法授权现在se配置开启全局方法授权 - 资源服务器检查token,通过认证管理器区检查token,调用userDetailservice,查询数据库的权限列表
//资源服务配置
@Configuration
@EnableResourceServer //开启资源服务配置
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig implements ResourceServerConfigurer {
//资源id
private static final String RESOURCE_ID="res1";
//资源服务安全性性配置
@Bean
public ResourceServerTokenServices resourceServerTokenServices(){
//使用远程服务请求授权服务效验token
RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
//请求中必须携带token
remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:4000/oauth/check_token");
//客户端的id
remoteTokenServices.setClientId("itsource");
//密钥
remoteTokenServices.setClientSecret("wyj");
return remoteTokenServices;
}
@Override
public void configure(ResourceServerSecurityConfigurer resourceServerSecurityConfigurer) throws Exception {
resourceServerSecurityConfigurer.resourceId(RESOURCE_ID)//资源id
.tokenServices(resourceServerTokenServices());//验证令牌
}
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers("/**").access("#oauth2.hasScope('emp')")//校验scope必须为all , 对应认证服务的客户端详情配置的clientId
.and().csrf().disable()//关闭跨越伪造检查
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//把session设置成无状态,使用了token不在用session做记录
}
}
版权声明:本文为weixin_45528650原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。