本文共 9450 字,大约阅读时间需要 31 分钟。
OAuth2是一种广泛用于授权管理的协议,主要用于规范令牌的发放过程。其最新版本为2.0,与之前的1.0不兼容,主要提供了四种授权模式:授权码模式、简化模式、密码模式和客户端模式。本文将重点介绍密码模式,因为前端系统采用用户名密码登录。
在密码模式中,用户向客户端提供用户名和密码,客户端通过认证服务器获取令牌。整个流程分为三个步骤:
我们需要一个完整的Spring Boot项目架构,以下是项目的POM文件配置:
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE demo security 0.0.1-SNAPSHOT security Spring Boot Security Demo Project 1.8 Greenwich.SR1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-oauth2 org.springframework.cloud spring-cloud-starter-security org.apache.commons commons-lang3 org.springframework.boot spring-boot-starter-data-redis io.jsonwebtoken jjwt 0.9.1 org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin
为了存储认证信息,我们选择Redis作为token存储。以下是Redis配置文件示例:
spring: redis: host: 127.0.0.1 port: 6379 password: KCl9HfqbVnhQ5c3n database: 0
定义一个安全配置类SecurityConfig,用于管理用户认证:
package com.example.demo.security.config;import com.example.demo.security.service.UserDetailService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.core.annotation.Order;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;@EnableWebSecurity@Order(2)public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailService userDetailService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatchers().antMatchers("/oauth/**") .and() .authorizeRequests() .antMatchers("/oauth/**").authenticated() .and() .csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder()); }} 定义一个资源服务器配置类ResourceServerConfig,用于管理资源访问权限:
package com.example.demo.security.config;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;@Configuration@EnableResourceServerpublic class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .requestMatchers().antMatchers("/**") .and() .authorizeRequests() .antMatchers("/**").authenticated(); }} 定义一个认证服务器配置类AuthorizationServerConfig,用于管理令牌颁发:
package com.example.demo.security.config;import com.example.demo.security.service.UserDetailService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.oauth2.config.annotation.configuers.ClientDetailsServiceConfigurer;import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;import org.springframework.security.oauth2.config.annotation.web.configuers.AuthorizationServerEndpointsConfigurer;import org.springframework.security.oauth2.provider.token.DefaultTokenServices;import org.springframework.security.oauth2.provider.token.TokenStore;import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private RedisConnectionFactory redisConnectionFactory; @Autowired private UserDetailService userDetailService; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("auth") .secret(passwordEncoder.encode("123456")) .authorizedGrantTypes("password", "refresh_token") .scopes("all"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.tokenStore(tokenStore()) .userDetailsService(userDetailService) .authenticationManager(authenticationManager) .tokenServices(defaultTokenServices()); } @Bean public TokenStore tokenStore() { return new RedisTokenStore(redisConnectionFactory); } @Primary @Bean public DefaultTokenServices defaultTokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore()); tokenServices.setSupportRefreshToken(true); tokenServices.setAccessTokenValiditySeconds(60 * 60 * 24); tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7); return tokenServices; }} 定义一个用户DetailsService类UserDetailService,用于用户认证:
package com.example.demo.security.service;import com.example.demo.security.entity.AuthUser;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.authority.AuthorityUtils;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.crypto.password.PasswordEncoder;import org.springframework.stereotype.Service;@Servicepublic class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { AuthUser user = new AuthUser(); user.setUsername(username); user.setPassword(passwordEncoder.encode("123456")); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("user:add")); }} 通过Postman测试可以验证系统的各个功能:
发送POST请求获取令牌:
发送GET请求获取资源:
发送DELETE请求注销令牌:
发送POST请求刷新令牌:
通过以上步骤,可以验证系统的完整认证流程是否正常工作。
转载地址:http://ms.baihongyu.com/