Spring Boot实现OAuth 2.0
2018-01-03 15:10
423 查看
忘记po源码了,点这里[github 源码]
开篇当然是包结构啦。
@SpringBootApplication
DataSourceAutoConfiguration.class }) //由于是多数据源,所以,屏蔽默认数据源设置
这一段在spring boot 1.59版本不需要写。当你有了自己的数据源配置后,spring boot会自动采用你自定义的配置。
也正是由于我多加了这段exclude导致@ResponseBody无法正确返回。而我以为是缺少了jpa jar。
public class QyApplication {
}
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
public class SecurityProvider implements AuthenticationProvider {
}
public class UserService implements UserDetailsService {
}
@EnableAuthorizationServer // 认证服务器注解
@EnableResourceServer //资源服务器注解
public class ServerConfig extends AuthorizationServerConfigurerAdapter {
}
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
}
public class ClientService implements ClientDetailsService {
}
至此,spring security的用户认证和OAuth2的客户端授权,已整合完成。
在这里点出几个坑:
开篇当然是包结构啦。
1.在app入口,添加@EnableAuthorizationServer注解,声明这是个认证服务器
@EnableAuthorizationServer@SpringBootApplication
【更正】
( scanBasePackages = {“com.qiyun.qy”}, exclude = {DataSourceAutoConfiguration.class }) //由于是多数据源,所以,屏蔽默认数据源设置
这一段在spring boot 1.59版本不需要写。当你有了自己的数据源配置后,spring boot会自动采用你自定义的配置。
也正是由于我多加了这段exclude导致@ResponseBody无法正确返回。而我以为是缺少了jpa jar。
public class QyApplication {
public static void main(String[] args) { SpringApplication.run(QyApplication.class, args); }
}
2.继承WebSecurityConfigurerAdapter,实现用户认证
@Configuration@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired @Qualifier("qiYunSecurityProvider") private AuthenticationProvider provider;// 自定义验证 @Autowired @Qualifier("qiYunUserService") private UserDetailsService userService; //查询用户 @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable()//禁用csrf (csrf会拦截所有post请求) .headers().frameOptions().disable()//允许使用iframe .and().authorizeRequests() .antMatchers("/home", "/register", "/socket").permitAll()//首页、注册、web socket,不需要权限 .antMatchers("/static/**", "/ueditor/**", "/error/**").permitAll() .antMatchers("/oauth/**", "/api/**").permitAll()//当前filter不拦截 OAuth2.0 的路径 .anyRequest().authenticated() .antMatchers("/admin/**").hasRole("admin")//预留管理员权限 .and().formLogin().defaultSuccessUrl("/home").permitAll() .and().logout().logoutUrl("/login?logout").logoutSuccessUrl("/").permitAll(); } @Autowired @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(provider); }
}
2.1 验证用户信息
@Service(“qiYunSecurityProvider”)public class SecurityProvider implements AuthenticationProvider {
@Autowired @Qualifier("qiYunUserService") private UserDetailsService userService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String name = authentication.getName(); String rawPassword = authentication.getCredentials().toString(); User user = (User) userService.loadUserByUsername(name); String sqlPassword = user.getPassword(); //加密 BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); if (!encoder.matches(rawPassword, sqlPassword)) { throw new BadCredentialsException("用户名或密码错误"); } List<GrantedAuthority> grantedAuths = user.getAuthorities(); return new UsernamePasswordAuthenticationToken(name, sqlPassword, grantedAuths); } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); }
}
2.2 查询用户信息
@Service(“qiYunUserService”)public class UserService implements UserDetailsService {
@Autowired IUserDao userDao; @Override public User loadUserByUsername(String name) throws UsernameNotFoundException { User user = userDao.findByUserKey(name); if (user == null) { throw new UsernameNotFoundException("用户不存在!"); } return user; }
}
3.OAuth2 client认证
@Configuration@EnableAuthorizationServer // 认证服务器注解
@EnableResourceServer //资源服务器注解
public class ServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired @Qualifier("baseDataSource") private DataSource dataSource; @Autowired @Qualifier("qiYunClientService") private ClientDetailsService clientService; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .allowFormAuthenticationForClients()//允许表单登录 .passwordEncoder(new BCryptPasswordEncoder());//client_secret的加密方式 } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource).clients(clientService); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore());//使用内存中的 token store //.authorizationCodeServices( //new JdbcAuthorizationCodeServices(dataSource)); //使用Jdbctoken store //.pathMapping("/oauth/token", "/oauth2/token");//自定义授权提交页面 } @Bean public TokenStore tokenStore(){ return new InMemoryTokenStore(); //使用内存中的 token store //return new JdbcTokenStore(dataSource); ///使用Jdbctoken store }
}
3.1 资源服务器配置
@Configuration@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
@Override public void configure(HttpSecurity http) throws Exception { http .requestMatchers().antMatchers("/api/**")//仅拦截api路径,与用户认证隔离 .and().authorizeRequests() .antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')") .antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')"); }
}
3.1 客户端查询
@Service(“qiYunClientService”)public class ClientService implements ClientDetailsService {
@Autowired private IClientDao clientDao; @Override public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException { Client client = clientDao.loadClientByClientId(clientId); return client; }
}
至此,spring security的用户认证和OAuth2的客户端授权,已整合完成。
在这里点出几个坑:
1.不指定client_secret的加密方式, 那么spring boot会采用默认的BCryptPasswordEncoder()。 如果此时你数据库里的client_secret字段值未加密, 恭喜你,会报加密错误。 (ps:当时忙着搭框架,没截图。有兴趣的,可以自己尝试) 2.获取accesss_token时,不缺少jackson的相关jar包, 却报错 no converter。本以为是源码里的ResponseEntiry导致的。 后来测试@ResponseBody也报错,才发现是框架打错了。 检查了一遍pom,发现是spring-boot-starter-data-jpa干掉了。 添加上依赖,OK。 【更正】:不是因为缺少了jpa的jar包,而是因为app入口上的类排除导致的。 3.关于客户端授权链接“/oauth/authorize? client_id=2&client_secret=secret& response_type=code &scope=read write trust &redirect_uri=http://127.0.0.1/home” 看网上都是用逗号分割scope。自己用逗号总报错。 看完源码,发现源码采用的分隔符是空格。 所以,请求链接中也需要用空格分割。 至于数据库中,可以用逗号, 然后在自己的ClientDetails类的getScope()中, 将字符串转换成Set<String>就行
相关文章推荐
- Spring boot 2.x+oauth2实现单点登录:基础准备之OAuth 2.0
- spring boot 集成quartz 2.0 实现前端动态配置(获取spring上下文)的两种方式,启动数据库中已开启定时任务
- 从零实现 Spring Boot 2.0 整合 weixin-java-mp(weixin-java-tools) 获取 openId,用于微信授权
- Security-OAuth2 密码模式之服务器实现(工具IDEA+Maven+springboot)
- 基于Spring Boot 2.0 及MongoDB 3.6.2 实现的简单文件共享服务器
- Spring Boot2.0整合ES5实现文章内容搜索实战
- Spring boot for Eclipse 开发指南第六节 Oauth 2.0
- 【Spring Boot 2.0】【Spring 事务的实现原理】 | Chat · 预告
- Spring Boot 2.0 利用 Spring Security 实现简单的OAuth2.0认证方式1
- 使用 Spring Boot 2.0 + WebFlux 实现 RESTful API功能
- 详解使用Spring Security OAuth 实现OAuth 2.0 授权
- Spring Boot 2.0 设置网站默认首页的实现代码
- 搭建nginx+tomcat+memcache三套集群,开发简单springboot工程,实现session共享(持续更新中)
- spring-boot 整合JSP实现java web动态应用程序
- 基于springboot+vue+element+ueditor实现前后端分离的富文本框实现
- SpringBoot项目在IntelliJ IDEA中实现热部署
- Spring Boot 定时任务实现后台管理动态配置(动态添加修改删除定时任务)
- springboot+webmagic实现java爬虫jdbc及mysql的方法
- 详解Spring Boot 定时任务的实现方法
- 基于Maven的SpringBoot项目实现热部署的两种方式