前文讲解实现了spring boot集成Oauth2.0,实现了授权服务器和资源服务器的搭建,并通过浏览器和postman测试,获取到了授权码,用携带授权码的URL能够争取范文到资源。
本文详细讲解spring boot集成Oauth2.0的几个重要文件接口,详细如下:
1、授权服务配置接口AuthorizationServerConfigurerAdapter
AuthorizationServerConfigurer接口,其中存在3个方法:
☆ AuthorizationServerSecurityConfigurer:配置令牌端点(Token Endpoint)的安全约束;
☆ ClientDetailsServiceConfigurer:配置OAuth2客户端;
☆ AuthorizationServerEndpointsConfigurer:配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services);
详细代码如下:bleAuthorizationServer
public class OAuthAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private OAuthWebSecurityConfig oauthWebSecurityConfig;
//AuthorizationServerSecurityConfigurer:配置令牌端点(Token ++Endpoint++)的安全约束;
//AuthorizationServerSecurityConfigurer继承自SecurityConfigurerAdapter,也就是一个 Spring Security安全配置提供给AuthorizationServer去配置AuthorizationServer的端点(/++oauth++/****)的安全访问规则、过滤器Filter。
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")//客户端token调用许可
.checkTokenAccess("permitAll()")//客户端校验token访问许可
.allowFormAuthenticationForClients();
}
//refresh_token 单独配置UserDetailsService
@Bean
public UserDetailsService userDetailsServiceRefresh_token() {
return oauthWebSecurityConfig.userDetailsService();
}
//AuthorizationServerEndpointsConfigurer:配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services);
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints // 设置令牌
.tokenStore(new JdbcTokenStore(dataSource)).userDetailsService(userDetailsServiceRefresh_token())
.authenticationManager(authenticationManager);
}
@Bean // 声明 ClientDetails实现
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
//ClientDetailsServiceConfigurer:配置OAuth2客户端;
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
}
2、资源服务配置接口ResourceServerConfigurerAdapter
ResourceServerConfigurerAdapter (资源服务器配置)内部关联了ResourceServerSecurityConfigurer 和 HttpSecurity。前者与资源安全配置相关,后者与http安全配置相关,详细代码如下:
/*** 资源服务器配置*/
@Configuration
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class OAuthResourcesServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
//在每个ResourceServer实例上设置resourceId,该resourceId作为该服务资源的唯一标识。(假如同一个微服务资源部署多份,resourceId相同)
private static final String DEMO_RESOURCE_ID = "test-resource";
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(DEMO_RESOURCE_ID); //配置resourceServerID
resources.tokenStore(new JdbcTokenStore(dataSource)); //...... 还可以有有其他的配置
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.cors()//开启跨域
.and()
.csrf().disable()
.logout()
.logoutUrl("/logout")//虚拟的登出地址
.and()
.authorizeRequests()
.antMatchers("/loginSuccess").permitAll()
.antMatchers("/loginSuccess.html").permitAll()
.antMatchers("/actuator/health").permitAll()
.anyRequest().authenticated();
}
}
3、web安全配置接口WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter是Spring Security提供了一个抽象类,实现了默认的认证和授权,允许用户自定义一个WebSecurity类,重写其中的三个configure来实现自定义的认证和授权,这三个方法如下:
- 自定义身份认证的逻辑
protected void configure(AuthenticationManagerBuilder auth) throws Exception { }
- 自定义全局安全过滤的逻辑
public void configure(WebSecurity web) throws Exception { }
- 自定义URL访问权限的逻辑
protected void configure(HttpSecurity http) throws Exception { }
详细代码如下:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class OAuthWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailServiceImpl myUserDetailServiceImpl;
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler;
@Autowired
private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
private DataSource dataSource;
/** * @return RememberMe 功能的 Repository */
@Bean
public PersistentTokenRepository persistentTokenRepository() {
// 连接数据库的实现类,还有一个实现类时存内存的InMemoryTokenRepositoryImpl
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
// 配置数据源
tokenRepository.setDataSource(dataSource);
// 在启动数据库时创建存储token的表
//tokenRepository.setCreateTableOnStartup(true);
return tokenRepository;
}
/******************************remember me***********************************/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/** 放行静态资源 */
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/swagger-ui.html");
web.ignoring().antMatchers("/swagger-resources/**");
web.ignoring().antMatchers("/v2/api-docs");
web.ignoring().antMatchers("/configuration/security");
web.ignoring().antMatchers("/configuration/ui");
//web.ignoring().antMatchers("/++webjars++ /++springfox++ -swagger-++ui++/**");
/************************************************************
* ++servlet++ 3.0 以上的版本支持直接访问 jar 包里面的资源文件。
* 访问方式:将 jar 包里的 META-INF/resources 目录看成根目录,
* 则这个目录下的文件都可以直接访问
* swagger-bootstrap-++ui++-1.9.6.jar资源放行*/
web.ignoring().antMatchers("/webjars/**");
web.ignoring().antMatchers("/doc.html");
web.ignoring().antMatchers("/loginSuccess");
web.ignoring().antMatchers("/loginSuccess.html");
web.ignoring().antMatchers("/loginError");
web.ignoring().antMatchers("/lock");
web.ignoring().antMatchers("/assets/**");
//路由跳转允许
web.ignoring().antMatchers("/api/**");
web.ignoring().antMatchers("/websocket/**"); //农村饮水安全
web.ignoring().antMatchers("/Serialnum/EnSure"); //序列号确认
web.ignoring().antMatchers("/lock"); //锁屏页面
web.ignoring().antMatchers("/login.html"); //序列号确认
//放行consul安全监测接口
web.ignoring().antMatchers("/v1");
web.ignoring().antMatchers("/actuator/health");
//web.ignoring().antMatchers("/loginError.html");
web.ignoring().antMatchers("/favicon.ico");
//放行单点登录
web.ignoring().antMatchers("/index");
web.ignoring().antMatchers("/index/**");
web.ignoring().antMatchers("/index/oauth_callback");
//web.ignoring().antMatchers("/myLogout");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers(HttpMethod.OPTIONS,"/login", "/oauth/authorize", "/oauth/token")
.and()
.cors()//开启跨域
.and()
.csrf().disable()
.requestMatchers()
.antMatchers("/login")
.antMatchers(HttpMethod.OPTIONS)
.antMatchers("/oauth/authorize")
.and()
.rememberMe()//记住我相关配置
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60*60*10)
//.antMatchers("/++oauth++/token")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
// 自定义登录页面,这里配置了 loginPage, 就会通过 LoginController 的 login 接口加载登录页面
// 登入成功后,跳转至指定页面
//.defaultSuccessUrl("/loginSuccess")
.failureUrl("/loginError").permitAll()
.and()
.logout()
.logoutUrl("/logout")//虚拟的登出地址
.logoutSuccessHandler(logoutSuccessHandler);
http.formLogin().failureHandler(customAuthenticationFailureHandler);
}
@Bean
@Override
public UserDetailsService userDetailsService(){
return myUserDetailServiceImpl;
//return userAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 配置用户名密码,这里采用内存方式,生产环境需要从数据库获取
// auth.inMemoryAuthentication()
// .withUser("++admin++")
// .password(passwordEncoder().encode("123"))
// .roles("USER");
// 使用自定义认证与授权
auth.userDetailsService(userDetailsService());
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
4、用户登录服务接口UserDetailsService
Spring Security中进行身份验证的是AuthenticationManager接口,ProviderManager是它的一个默认实现,但它并不用来处理身份认证,而是委托给配置好的AuthenticationProvider,每个AuthenticationProvider会轮流检查身份认证。检查后或者返回Authentication对象或者抛出异常。验证身份就是加载响应的UserDetails,看看是否和用户输入的账号、密码、权限等信息匹配。UserDetails中需要重定义loadUserByUsername()函数。
详细代码如下:
@Component
public class MyUserDetailServiceImpl implements UserDetailsService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private SysUserService sysUserService;
@Autowired
private SysUserMapper sysUserMapper;
/**
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) {
SysUser sysUser = sysUserMapper.findByName(username);
if(sysUser==null) {
logger.info("-------------未查询到用户名:" + username);
throw new UsernameNotFoundException("Invalid username or password.");
}else {
Boolean stateStr=sysUser.getAccountNonLocked();//锁定状态
if(stateStr==false){//用户被锁定
long lockTime = sysUser.getLockTime();
long sysTime = System.currentTimeMillis();
long time = sysTime - lockTime;
if(time>=10*60*1000) { //时间超过10分钟,解锁账户
sysUserMapper.updateUNLockedByUserId(username);
sysUserMapper.updatelockTimeByUserId(username, 0L);
sysUserMapper.updatenLockByUserId(username, 0L);
stateStr=true;
}else {
throw new InternalAuthenticationServiceException("该账号已被锁定,请联系管理员!");
}
}
Set<String> permissions = sysUserService.findPermissions(username);
List<GrantedAuthority> grantedAuthorities = permissions.stream().map(GrantedAuthorityImpl::new).collect(Collectors.toList());
return new User(username,
//encryptedPassWord,
sysUser.getPassword(),
true,
true,
true,
stateStr, //锁定状态
grantedAuthorities);
}
}
}
5、授权失败接口SimpleUrlAuthenticationFailureHandler
在Spring Security Web框架内部,缺省使用的认证错误处理策略是AuthenticationFailureHandler的实现类SimpleUrlAuthenticationFailureHandler。它由配置指定一个defaultFailureUrl,表示认证失败时缺省使用的重定向地址。一旦认证失败,它的方法onAuthenticationFailure被调用时,它就会将用户重定向到该地址。如果该属性没有设置,它会向客户端返回一个401状态码。另外SimpleUrlAuthenticationFailureHandler还有一个属性useForward,如果该属性设置为true,页面跳转将不再是重定向(redirect)机制,取而代之的是转发(forward)机制。
该处只需要重定义onAuthenticationFailure()详细代码如下:
//3、将登录失败提示到前端展示
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private static ObjectMapper ++objectMapper++ = new ObjectMapper();
@Autowired
private ThymeleafViewResolver ++viewResolver++;
private RedirectStrategy ++redirectStrategy++ = new DefaultRedirectStrategy();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//此处自行定义授权失败功能。
}
}
springboot集成Oauth2.0授权包,接口文件配置详解到此就结束了,学友在实际操作过程中遇到问题,欢迎联系博主。
下文讲解spring cloud的配置与应用,实现服务注册机制。