一、添加依赖
在这里我们也需要导入redis的相关依赖,因为实际使用过程,需要人为干预令牌的有效时间
<!--Oauth2依赖--> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>${security-oauth2-version}</version> </dependency> <!--使用jwt令牌--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>${jwt-version}</version> </dependency> <!-- 配置使用redis启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${redis-jedis-version}</version> </dependency> <!--fastjson转换--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${alibaba-fastjon-version}</version> </dependency>
二、生成jks证书
在导入依赖包后, 我们需要再redsources文件下创建配置文件application.yml,在这里我们不做过多的说明,我们要使用到JWT安全证书,并通过证书生成令牌,并将生成的证书文件xxx.jks放到resources文件下。
三、创建SecurityConfiguration.java实体类,并让其继承WebSecurityConfigurerAdapt,其中myUserDetailsServiceImpl是进行验证登陆者账号和密码的实体类
@Configuration @EnableWebSecurity class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter { @Resource(name = "myUserDetailsServiceImpl") private UserDetailsService userDetailsService; @Override public void configure(WebSecurity web) throws Exception { //用户登录认证、用户退出、用户获取jwt令牌 web.ignoring().antMatchers("/XXX"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { AuthenticationManager manager = super.authenticationManagerBean(); return manager; } @Override protected UserDetailsService userDetailsService() { return userDetailsService; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } //采用bcrypt对密码进行编码 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(HttpSecurity http) throws Exception { // http.csrf().disable() // .httpBasic().and() // .formLogin() // .and() // .authorizeRequests().anyRequest().authenticated(); http.authorizeRequests().anyRequest().permitAll().and().csrf().disable(); } }
四、UserDetailsServiceImpl实体类,我们可以看到这里做了账号密码验证并且使用了加密
五、创建实体类AuthServerConfig.java实体类,该实体类做了关于oauth2客户端的一些配置
@Configuration @EnableAuthorizationServer public class CustomAuthServerConfig extends AuthorizationServerConfigurerAdapter { /*jwt令牌转换器*/ @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; /*在这里userDetailService一定要加上@Autowired,否则会报错找不到服务器UserDetailsService is required*/ @Resource(name = "myUserDetailsServiceImpl") UserDetailsService userDetailsService; @Autowired AuthenticationManager authenticationManager; @Autowired TokenStore tokenStore; @Autowired PasswordEncoder passwordEncoder; @Autowired private SecurityAuth securityAuth; /* 授权服务器的安全配置*/ @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer .tokenKeyAccess("permitAll()") .allowFormAuthenticationForClients() /*校验token需要认证通过,可采用http basic认证*/ .checkTokenAccess("isAuthenticated()"); } /*设置认证请求相关参数,例如客户端账号和密码、令牌有效时间等等*/ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient(securityAuth.getClientId())/*客户端id*/ .secret(passwordEncoder.encode(securityAuth.getClientSecret()))/*密码,要保密*/ .accessTokenValiditySeconds(60 * 60 * X)/*访问令牌有效期X个小时*/
.refreshTokenValiditySeconds(60 * 60 * X)/*刷新令牌有效期X个小时*/
/*授权客户端请求认证服务的类型authorization_code:根据授权码生成令牌, client_credentials:客户端认证,refresh_token:刷新令牌,password:密码方式认证*/ .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password") .redirectUris("http://localhost") .scopes("app");/*客户端范围,名称自定义,必填*/ } @Bean public TokenEnhancer customTokenEnhancer() { return new CustomTokenEnhancer(); } /*授权服务器端点配置*/ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { /*endpoints.authenticationManager(authenticationManager)认证管理器 .userDetailsService(userDetailsService);/*用户信息service*/ /*将增强的token设置到增强链中*/ TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(), jwtAccessTokenConverter())); endpoints.accessTokenConverter(jwtAccessTokenConverter) .authenticationManager(authenticationManager)/*认证管理器*/ .tokenStore(tokenStore)/*令牌存储*/ .userDetailsService(userDetailsService)/*用户信息service*/ .tokenEnhancer(enhancerChain);//自定义jwt令牌中的携带参数 } //使用证书文件生成jwt令牌的 @Bean @Autowired public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { return new JwtTokenStore(jwtAccessTokenConverter); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { /* 证书文件*/ String key_location = "XXXX.jks";
/*密钥库密码*/ String keystore_password = "XXXX";
/*访问证书路径*/ ClassPathResource resource = new ClassPathResource(key_location); /*密钥工厂*/ KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, keystore_password.toCharArray()); /*密钥别名*/ String alias = "XXXX";
/*密钥库密码*/ String keypassword = "XXXX"; KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, keypassword.toCharArray()); JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setKeyPair(keyPair); return converter; } }
这样认证服务器的配置参数就完成了,启动服务后,我们就可以测试发送验证请求,因为在这里我们仅仅叙述的是功能的实现,账号密码都用一些最简单的,这块的业务逻辑,可以根据实际情况去编写,是否能获取到返回的令牌
六、测试
密码模式测试
Post请求:http://localhost:8080/oauth/token
参数:
grant_type:密码模式授权填写password
username:账号
password:密码
此链接需要使用http Basic认证,这点需要注意以下,http Basic中认证信息的username和password就写我们之前在代码中预先写好的内容
access_token:访问令牌,携带此令牌访问资源
token_type:在请求资源的时候,在令牌之前加上该信息,并且空一格
refresh_token:刷新令牌,使用此令牌可以延长访问令牌的过期时间
expires_in:过期时间,单位为秒
scope:范围,与定义的客户端范围一致
看到以上信息的时候,恭喜你测试成功!