赞
踩
springcloudsecurity+oauth+redis+mybatisplus实现授权认证(基于授权码模式)
理解OAuth 2.0:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
1.技术栈;springboot+springcloudsecurity+mybatisplus
oAuth 在 “客户端” 与 “服务提供商” 之间,设置了一个授权层(authorization layer)。“客户端” 不能直接登录 “服务提供商”,只能登录授权层,以此将用户与客户端区分开来。“客户端” 登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。“客户端” 登录授权层以后,“服务提供商” 根据令牌的权限范围和有效期,向 “客户端” 开放用户储存的资料
1.AuthorizationServerConfiguration.java
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private DataSource dataSource; @Autowired private AuthenticationManager authenticationManager; @Autowired private RedisConnectionFactory redisConnectionFactory; /* @Bean public TokenStore tokenStore() { // 基于 JDBC 实现,令牌保存到数据库 return new JdbcTokenStore(dataSource); }*/ //令牌保存到Redis*/ @Bean public TokenStore tokenStore() { RedisTokenStore redisToken = new RedisTokenStore(redisConnectionFactory); return redisToken; } @Bean public ClientDetailsService jdbcClientDetails() { // 基于 JDBC 实现,需要事先在数据库配置客户端信息 return new JdbcClientDetailsService(dataSource); } /** * 在此处定义认证管理,即系统或者集群中的用户以及 Token的存儲方式, 定义授权、token终端、token服务 */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 自定义token生成方式,增加用户登录名等信息 TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(new MyTokenEnhancer())); //通过注入authenticationManager 会自动开启password grants // 设置令牌 endpoints .authenticationManager(authenticationManager) .tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain) .userDetailsService(userDetailsService) .exceptionTranslator(e -> { if (e instanceof OAuth2Exception) { OAuth2Exception oAuth2Exception = (OAuth2Exception) e; return ResponseEntity .status(HttpStatus.UNAUTHORIZED) .body(new CustomOauthException(oAuth2Exception.getMessage())); } else { throw e; } }); } /** * 支持刷新token * * @return DefaultTokenServices */ @Primary @Bean public AuthorizationServerTokenServices tokenServices() { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setAccessTokenValiditySeconds(60000); defaultTokenServices.setRefreshTokenValiditySeconds(604800); defaultTokenServices.setSupportRefreshToken(true); defaultTokenServices.setReuseRefreshToken(false); defaultTokenServices.setTokenStore(tokenStore()); return defaultTokenServices; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 读取客户端配置 clients.withClientDetails(jdbcClientDetails()); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { //允许表单认证 oauthServer.allowFormAuthenticationForClients(); //允许 check_token 访问 oauthServer.checkTokenAccess("permitAll()"); }
2.WebSecurityConfiguration.java
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)//全局方法拦截 public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Bean public BCryptPasswordEncoder passwordEncoder() { // 设置默认的加密方式 return new BCryptPasswordEncoder(); } @Bean public DaoAuthenticationProvider authProvider() { final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(passwordEncoder()); return authProvider; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 使用自定义认证与授权 auth .authenticationProvider(authProvider()) .userDetailsService(userDetailsService()) .passwordEncoder(passwordEncoder()); } @Override public void configure(WebSecurity web) throws Exception { // 将 check_token 暴露出去,否则资源服务器访问时报 403 错误 web.ignoring().antMatchers("/oauth/check_token"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * 通过HttpSecurity实现Security的自定义过滤配置 * @param http * @throws Exception */ @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http .requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**") .and() .authorizeRequests() .antMatchers("/oauth/**").authenticated() .and() .formLogin().permitAll(); //新增login form支持用户登录及授权 } }
3.UserDetailsServiceImpl.java
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private TbPermissionService tbPermissionService; @Autowired private TbUserService tbUserService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { TbUser tbUser = tbUserService.queryTbUserByUserName(username); List<GrantedAuthority> grantedAuthorities = new ArrayList(); if (StringUtils.isEmpty(tbUser)) { throw new UsernameNotFoundException("很抱歉,找不到用户名为" + username + "的用户!"); } if (tbUser != null) { List<TbPermission> tbPermissions = tbPermissionService .queryPermissionByUserId(tbUser.getId()); tbPermissions.forEach(tbPermission -> { if (tbPermission != null && tbPermission.getEnname() != null) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(tbPermission.getEnname()); grantedAuthorities.add(grantedAuthority); } }); } /** * 若只是认证,要去掉grantedAuthorities换成 Collections.emptyList() * 若是要授权,要加上 */ CustomUserPrincipal userDetail = new CustomUserPrincipal(tbUser.getUsername(), tbUser.getPassword(), grantedAuthorities); userDetail.setTbUser(tbUser); return userDetail; }
4.ResourceServerConfiguration.java
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Autowired private RedisConnectionFactory redisConnectionFactory; /*@Autowired private DataSource dataSource; @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); }*/ // @Bean public TokenStore tokenStore() { return new RedisTokenStore(redisConnectionFactory); } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { //resourceId 推荐每个 受保护的资源都提供一下 ,可以供 auth服务对资源进行一个认证 resources.resourceId("ls_resource").tokenStore(tokenStore()); } @Override public void configure(HttpSecurity http) throws Exception { http .exceptionHandling() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() // 以下为配置所需保护的资源路径及权限,需要与认证服务器配置的授权部分对应 .antMatchers("/contents").hasAuthority("SystemContent") .antMatchers("/view/**").hasAuthority("SystemContentView") .antMatchers("/insert/**").hasAuthority("SystemContentInsert") .antMatchers("/update/**").hasAuthority("SystemContentUpdate") .antMatchers("/delete/**").hasAuthority("SystemContentDelete"); } }
5.localhost:8080/oauth/authorize?client_id=client&response_type=code获取code
用户名:admin 密码:123456
6.获取token
7.访问资源
8.其他代码请见GitHub:https://github.com/ls65535/springcloud/tree/master/auth-oauth2
参考:
https://www.funtl.com/zh/guide/Spring-Security-oAuth2.html
https://www.cnblogs.com/cjsblog/p/10548022.html
https://blog.csdn.net/w1054993544/article/details/78932614
阮一峰的jwt入门教程:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
阮一峰理解OAuth2.0: https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。