OAuth2与spring

编程入门 行业动态 更新时间:2024-10-10 14:25:58

OAuth2与<a href=https://www.elefans.com/category/jswz/34/1769862.html style=spring"/>

OAuth2与spring

OAuth2与spring-security-oauth2

  • OAuth2
    • OAuth2是什么
    • OAuth2中4种授权模式作用场景
  • spring-security-oauth2
    • spring-security-oauth2是什么
    • 搭建spring-security-oauth2案例
      • 环境版本
      • pom.xml
      • application.yml
    • 目录结构
    • 密码模式
      • 获取token
      • 访问受保护的资源
    • 授权码模式
      • 获取code
      • 获取token
      • 访问受保护的资源
  • 结语

OAuth2

OAuth2是什么

关于这块概念可以参考:

OAuth2中4种授权模式作用场景

  1. 授权码模式
    授权码模式一般用于提供给第三方使用
  2. 简化模式
    简化模式一般不会使用
  3. 密码模式
    密码模式一般仅用于系统内部使用
  4. 客户端凭证模式
    客户端凭证模式一般不会使用

spring-security-oauth2

spring-security-oauth2是什么

spring-security-oauth2是基于spring-security框架完整实现oauth2协议的框架,具有oauth2中4种模式访问和第三方登录等功能。

搭建spring-security-oauth2案例

环境版本

	<properties><java.version>1.8</java.version><spring.cloud.version>Hoxton.SR9</spring.cloud.version><spring.boot.version>2.3.0.RELEASE</spring.boot.version><mysql.connector.version>8.0.15</mysql.connector.version></properties>

pom.xml

	<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-jwt</artifactId><version>1.1.0.RELEASE</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.connector.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring.boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring.cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

application.yml


server:port: 8080spring:datasource:url: jdbc:mysql://192.168.174.129:3306/oauth?serverTimezone=GMT%2B8&characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=trueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

目录结构

DemoAuthorizationServerConfiguration:授权服务配置

@Configuration
@EnableAuthorizationServer
@AllArgsConstructor
public class DemoAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {private DataSource dataSource;private TokenStore tokenStore;private AuthenticationManager authenticationManager;private UserDetailsService userDetailsService;private TokenEnhancer tokenEnhancer;private JwtAccessTokenConverter jwtAccessTokenConverter;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {// @formatter:offclients.inMemory().withClient("test-client").secret("$2a$08$YGw560YLRWHg3Hl29ZlmdOfAeyRQ2u0kDiqUyQ62Y1pkW5n4a.hjO").authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit").authorities("ROLE_CLIENT").redirectUris("http://localhost:8084/oauth/callback").scopes("read", "write", "all");// 请求参数scope必须为集合中的某个值// @formatter:on}@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {// 允许表单传参client信息security.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.tokenStore(tokenStore).authenticationManager(authenticationManager).userDetailsService(userDetailsService).tokenEnhancer(tokenEnhancer).accessTokenConverter(jwtAccessTokenConverter);}}

DemoJwtTokenStoreConfiguration:JwtToken仓库配置

@Configuration
public class DemoJwtTokenStoreConfiguration {@Beanpublic TokenStore tokenStore(JwtAccessTokenConverter tokenConverter) {return new JwtTokenStore(tokenConverter);}@Beanpublic JwtAccessTokenConverter tokenConverter() {JwtAccessTokenConverter tokenConverter = new JwtAccessTokenConverter();tokenConverter.setSigningKey("abc");return tokenConverter;}@Beanpublic TokenEnhancer tokenEnhancer(JwtAccessTokenConverter tokenConverter) {return new DemoJwtTokenEnhancer(tokenConverter);}}

DemoResourceServerConfiguration:资源服务配置

@Configuration
@EnableResourceServer
@AllArgsConstructor
public class DemoResourceServerConfiguration extends ResourceServerConfigurerAdapter {private AccessDeniedHandler accessDeniedHandler;//	private AuthenticationEntryPoint authenticationEntryPoint;@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().exceptionHandling().accessDeniedHandler(accessDeniedHandler)
//				.authenticationEntryPoint(authenticationEntryPoint).and().csrf().disable();}@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {super.configure(resources);}}

DemoWebSecurityConfiguration:WebSecurity配置

@Configuration
public class DemoWebSecurityConfiguration extends WebSecurityConfigurerAdapter {@Bean@Override@SneakyThrowspublic AuthenticationManager authenticationManagerBean() {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder(BCryptPasswordEncoder.BCryptVersion.$2A, 8);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.httpBasic().and().csrf().disable();}
}

DemoController:受保护的Controller资源

@RestController
@RequestMapping("/api")
public class DemoController {@RequestMapping("/test")public Map<String, Object> test() {Map<String, Object> result = new HashMap<>();result.put("time", System.currentTimeMillis());return result;}}

DemoClientDetailsService:ClientDetailsService实现类

public class DemoClientDetailsService extends JdbcClientDetailsService {public DemoClientDetailsService(DataSource dataSource) {super(dataSource);}}

DemoUserDetails:用户信息类

@Getter
public class DemoUserDetails extends User {/*** 用户id*/private String userId;/*** 手机号*/private String mobile;/*** 是否超级管理员 1是 0否*/private Boolean administrator;/*** 角色id*/private List<Long> roles;public DemoUserDetails(String userId, String mobile, String username, String password, boolean enabled, List<Long> roles, boolean accountNonExpired,boolean credentialsNonExpired, boolean accountNonLocked,Collection<? extends GrantedAuthority> authorities, Boolean administrator) {super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked,authorities);this.userId = userId;this.roles = roles;this.administrator = administrator;this.mobile = mobile;}}

DemoUserDetailsServiceImpl:UserDetailsService实现类

@Service
public class DemoUserDetailsServiceImpl implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {return new DemoUserDetails("userId", "mobile", s, "$2a$08$EiGfaup8QkkjT6DhvCSFRuNhdFTEV7Rbu/avUm8lGL2ZUji/lTWji", true, Arrays.asList(1L), true, true, true,AuthorityUtilsmaSeparatedStringToAuthorityList("1,2"), false);}}

DemoAccessDeniedHandler:403处理器

@Component
public class DemoAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);httpServletResponse.setContentType("application/json;charset=UTF-8");PrintWriter out = httpServletResponse.getWriter();out.write(new ObjectMapper().writeValueAsString("权限不足,请联系管理员!"));out.flush();out.close();}}

DemoAuthenticationEntryPoint:401处理器

//@Component
public class DemoAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);httpServletResponse.setContentType("application/json;charset=UTF-8");PrintWriter out = httpServletResponse.getWriter();out.write(new ObjectMapper().writeValueAsString("请先登录!"));out.flush();out.close();}}

DemoJwtTokenEnhancer:TokenEnhancer实现类

@AllArgsConstructor
public class DemoJwtTokenEnhancer implements TokenEnhancer {private JwtAccessTokenConverter jwtAccessTokenConverter;@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {DemoUserDetails principal =(DemoUserDetails) authentication.getUserAuthentication().getPrincipal();Map<String, Object> info = new HashMap<>();info.put("user_id", principal.getUserId() == null ? "" : String.valueOf(principal.getUserId()));((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);return jwtAccessTokenConverter.enhance(accessToken, authentication);}}

DemoPasswordEncoder:PasswordEncoder实现类

public class DemoPasswordEncoder implements PasswordEncoder {@Overridepublic String encode(CharSequence rawPassword) {return (String) rawPassword;}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return encodedPassword.equals(encode(rawPassword));}}

密码模式

获取token

/oauth/token,获取token,access_token就是我们需要在请求头中携带的token。

访问url:
http://localhost:8080/oauth/token?username=admin&password=qwer1234&grant_type=password&scope=all
并在请求头中加入basic auth参数
眼力好的同学已经看出来上图中已经在url中出现了client…
也可以直接访问这个url:
http://localhost:8080/oauth/token?username=admin&password=qwer1234&grant_type=password&scope=all&client_id=test-client&client_secret=abc
这种访问方式又是哪里出来的?第一个java代码块里面就有配置了…
allowFormAuthenticationForClients又是怎么实现的呢?

	@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {// 允许表单传参client信息security.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}

访问受保护的资源

访问受保护的资源
图片中就是在请求头中将入key为Authorization的值
Authorization Bearer eyJhbGciOiJ…

授权码模式

获取code

直接在浏览器上访问该链接
http://localhost:8080/oauth/authorize?response_type=code&scope=all&client_id=test-client&client_secret=abc&redirect_uri=http://localhost:8084/oauth/callback

浏览器弹出httpBasic验证
输入预设用户名/密码:admin/qwer1234
点击确定,弹出OAuth2用户授权页面,点击授权Authorize
页面重定向到redirect_uri参数指定的url并附带了code

获取token

使用上一步中获取的code替换下面的,并访问url:
http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=test-client&client_secret=abc&redirect_uri=http://localhost:8084/oauth/callback&code=OWwAmR

不会有人直接复制链接不改code参数吧?不会吧,不会吧

访问受保护的资源

该步骤与密码模式中一致

结语

spring-security-oauth2秉承spring一贯风格特色,配置多种多样,如果见到和上面配置不一样很正常,如果想要深入了解,需要仔细阅读源码。上面的案例只是简单的入门描述,由此可以引发很多疑问。

  1. 使用数据库配置client与user怎么做
  2. 需要配置手机号验证码登录等其他方式需要怎么做
  3. 授权码模式需要用户手动授权,如果特殊情况下改为不需要授权怎么做
  4. 需要在网关中使用,该怎么做
  5. 需要权限验证,该怎么做
  6. 基于spring-security-oauth2框架的单点登录怎么做

关注点赞,下次继续更新

配置篇 spring-security-oauth2 配置(一)

源码分析篇A路线 spring-security-oauth2 源码分析A路线(一)

源码分析篇B路线 spring-security-oauth2 源码分析B路线(一)

更多推荐

OAuth2与spring

本文发布于:2024-03-10 19:16:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1728818.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:spring

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!