`
rensanning
  • 浏览: 3509683 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
Efef1dba-f7dd-3931-8a61-8e1c76c3e39f
使用Titanium Mo...
浏览量:37404
Bbab2146-6e1d-3c50-acd6-c8bae29e307d
Cordova 3.x入门...
浏览量:603960
C08766e7-8a33-3f9b-9155-654af05c3484
常用Java开源Libra...
浏览量:677498
77063fb3-0ee7-3bfa-9c72-2a0234ebf83e
搭建 CentOS 6 服...
浏览量:86981
E40e5e76-1f3b-398e-b6a6-dc9cfbb38156
Spring Boot 入...
浏览量:399561
Abe39461-b089-344f-99fa-cdfbddea0e18
基于Spring Secu...
浏览量:68981
66a41a70-fdf0-3dc9-aa31-19b7e8b24672
MQTT入门
浏览量:90291
社区版块
存档分类
最新评论

Spring Security OAuth2 Provider 之 自定义开发

 
阅读更多
Spring OAuth2默认提供的功能难免无法满足需求,需要特殊定制,这里列举常见的几个需要特殊开发的地方。

相关文章:
Spring Security OAuth2 Provider 之 最小实现
Spring Security OAuth2 Provider 之 数据库存储
Spring Security OAuth2 Provider 之 第三方登录简单演示
Spring Security OAuth2 Provider 之 自定义开发
Spring Security OAuth2 Provider 之 整合JWT

(1)自定义生成授权码

默认规则是:6位随机英数字。
可以通过扩展AuthorizationCodeServices来覆写已有的生成规则。通过覆写createAuthorizationCode()方法可以设置成任意的生成规则。
比如,这里实现返回32位随机英数字。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

	@Bean
	protected AuthorizationCodeServices authorizationCodeServices() {
	    return new CustomJdbcAuthorizationCodeServices(dataSource());
	}

}

public class CustomJdbcAuthorizationCodeServices extends JdbcAuthorizationCodeServices {

	private RandomValueStringGenerator generator = new RandomValueStringGenerator();
	
	public CustomJdbcAuthorizationCodeServices(DataSource dataSource) {
		super(dataSource);
		this.generator = new RandomValueStringGenerator(32);
	}
	
	public String createAuthorizationCode(OAuth2Authentication authentication) {
		String code = this.generator.generate();
		store(code, authentication);
		return code;
	}

}


效果如下:


(2)自定义生成令牌

默认规则是:UUID。
Spring OAuth2提供了一个操作Token的接口TokenEnhancer,通过实现它可以任意操作accessToken和refreshToken。比如,这里实现将Token中的横线去掉。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

	@Bean
	public TokenEnhancer tokenEnhancer() {
	    return new CustomTokenEnhancer();
	}

}

public class CustomTokenEnhancer implements TokenEnhancer {

	@Override
	public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
		if (accessToken instanceof DefaultOAuth2AccessToken) {
			DefaultOAuth2AccessToken token = ((DefaultOAuth2AccessToken) accessToken);
			token.setValue(getNewToken());
			
			OAuth2RefreshToken refreshToken = token.getRefreshToken();
			if (refreshToken instanceof DefaultOAuth2RefreshToken) {
				token.setRefreshToken(new DefaultOAuth2RefreshToken(getNewToken()));
			}
			
			Map<String, Object> additionalInformation = new HashMap<String, Object>();
			additionalInformation.put("client_id", authentication.getOAuth2Request().getClientId());
			token.setAdditionalInformation(additionalInformation);
			
			return token;
		}
		return accessToken;
	}
	
	private String getNewToken() {
		return UUID.randomUUID().toString().replace("-", "");
	}

}


效果如下:


(3)自定义授权页面

默认的定义如下:
org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint
引用
  private String userApprovalPage = "forward:/oauth/confirm_access";
  private String errorPage = "forward:/oauth/error";


org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint
引用
  @RequestMapping({"/oauth/confirm_access"})
  public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
    // ...
  }


org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint
引用
  @RequestMapping({"/oauth/error"})
  public ModelAndView handleError(HttpServletRequest request) {
    // ...
  }


设置新的URL:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthorizationEndpoint authorizationEndpoint;

    @PostConstruct
    public void init() {
        authorizationEndpoint.setUserApprovalPage("forward:/oauth/my_approval_page");
        authorizationEndpoint.setErrorPage("forward:/oauth/my_error_page");
    }
}


页面实现:
@Controller
@SessionAttributes({ "authorizationRequest" })
public class OAuthController {

	@RequestMapping({ "/oauth/my_approval_page" })
	public String getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
		@SuppressWarnings("unchecked")
		Map<String, String> scopes = (Map<String, String>) (model.containsKey("scopes") ? model.get("scopes") : request.getAttribute("scopes"));
		List<String> scopeList = new ArrayList<String>();
		for (String scope : scopes.keySet()) {
			scopeList.add(scope);
		}
		model.put("scopeList", scopeList);
		return "oauth_approval";
	}

	@RequestMapping({ "/oauth/my_error_page" })
	public String handleError(Map<String, Object> model, HttpServletRequest request) {
		Object error = request.getAttribute("error");
		String errorSummary;
		if (error instanceof OAuth2Exception) {
			OAuth2Exception oauthError = (OAuth2Exception) error;
			errorSummary = HtmlUtils.htmlEscape(oauthError.getSummary());
		} else {
			errorSummary = "Unknown error";
		}
		model.put("errorSummary", errorSummary);
		return "oauth_error";
	}
}


/src/main/resources/templates/oauth_approval.html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
  <title>approval</title>
  <meta charset="utf-8"/>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-md-12 well">
        <h3>授权页</h3>
        应用名 : <span th:text="${session.authorizationRequest.clientId}">clientId</span>

		<form id='confirmationForm' name='confirmationForm' th:action="@{/oauth/authorize}" method='post'>
			<input name='user_oauth_approval' value='true' type='hidden' />
			<input th:name="${s}" value="true" type="hidden" th:each="s : ${scopeList}" />
			<input name='authorize' value='授权' type='submit' />
		</form>
	  </div>
    </div>
  </div>
</body>
</html>


/src/main/resources/templates/oauth_error.html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
  <title>error</title>
  <meta charset="utf-8"/>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-md-12 well">
        <h3>错误</h3>
        <p style="color:red;">出错了!不能继续授权操作!</p>
        <p th:utext="${errorSummary}">errorSummary
      </div>
    </div>
  </div>
</body>
</html>


效果如下:



(4)自定义用户登录页面
这部分应该属于SpringSecurity范畴的。

创建用户表
CREATE TABLE account
(
  id serial NOT NULL,
  user_name character varying(50),
  email character varying(255),
  password character varying(512),
  role_string character varying(50),
  CONSTRAINT account_pkey PRIMARY KEY (id)
);

INSERT INTO account(user_name, email, password, role_string)
    VALUES ('user', 'user@sample.com', '123', 'ROLE_USER');


配置SpringSecurity
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebSecurity
static class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.csrf().disable();

      http.antMatcher("/oauth/**")
        .authorizeRequests()
          .antMatchers("/oauth/index").permitAll()
          .antMatchers("/oauth/token").permitAll()
          .antMatchers("/oauth/check_token").permitAll()
          .antMatchers("/oauth/confirm_access").permitAll()
          .antMatchers("/oauth/error").permitAll()
          .antMatchers("/oauth/my_approval_page").permitAll()
          .antMatchers("/oauth/my_error_page").permitAll()
          .anyRequest().authenticated()
        .and()
          .formLogin()
          .loginPage("/oauth/index")
          .loginProcessingUrl("/oauth/login");
    }
    @Autowired
    private CustomAuthenticationProvider authenticationProvider;
}

@Configuration
@MapperScan("com.rensanning")
@EnableTransactionManagement(proxyTargetClass = true)
static class RepositoryConfig {
}


用户登录处理部分
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

  @Autowired
  private AccountService accountService;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    String name = authentication.getName();
    String password = authentication.getCredentials().toString();

    Account account = accountService.authUser(name, password);
    if (account == null) {
      throw new AuthenticationCredentialsNotFoundException("Account is not found.");
    }

    List<GrantedAuthority> grantedAuths = AuthorityUtils.createAuthorityList(account.getRoleString());
    return new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }
}

@Service
public class AccountService {

  @Autowired
  private AccountRepository accountRepository;

  public Account authUser(String userName, String password) {
    Account u = accountRepository.findByUserName(userName);
    if (u == null) {
      return null;
    }
    if (!u.getPassword().equals(password)) {
      return null;
    }
    return u;
  }

}

public interface AccountRepository {
  @Select("select id, user_name as userName, email, password, role_string as roleString from account where user_name=#{user_name}")
  Account findByUserName(String userName);
}

@SuppressWarnings("serial")
public class Account implements Serializable {
  private Integer id;
  private String userName;
  private String email;
  private String password;
  private String roleString;
  // ...setter/getter
}



完成的Client->ResoureServer->AuthServer的执行过程:


参考:
https://stackoverflow.com/questions/29618658/spring-how-to-create-a-custom-access-and-refresh-oauth2-token
https://stackoverflow.com/questions/29345508/spring-oauth2-custom-oauth-approval-page-at-oauth-authorize
  • 大小: 17.6 KB
  • 大小: 74.2 KB
  • 大小: 26 KB
  • 大小: 29.9 KB
  • 大小: 15.9 KB
  • 大小: 7.7 KB
  • 大小: 93.5 KB
1
1
分享到:
评论
3 楼 IT小新 2017-10-27  
求该例子得示例代码呗,谢谢了
2 楼 xu_yuan 2017-10-24  
LS少写了thymeleaf的配置,如果不加的话,是不能识别thymeleaf语法的html文件的。会导致controller虽然返回了oauth_approval,但是却报错error 找不到mapping

配置自定义授权页
POM.xml 需要加入以下配置
		<!---模板引擎:网页路径渲染-->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>


application.yml 需要加入以下配置
spring:
  thymeleaf:
    prefix: classpath:/templates/ # 模板路径
1 楼 ihanfeng 2017-08-31  
本例有没有相关代码实例,根据你上面的配置没搞成功,登录后又返回登录页面。

相关推荐

    Spring Security OAuth2 Provider 之 第三方登录简单演示

    NULL 博文链接:https://rensanning.iteye.com/blog/2386309

    oauth2-family-barrel:OAuth2全家桶项目。本项目演示了如何使用spring-boot,spring-security以及spring-security-oauth快速构建OAuth2服务框架体系

    oauth2-family-barrel OAuth2全家桶 什么是oauth2-family-barrel oauth2-family-barrel项目,即OAuth2全家桶项目。 本项演示了如何使用 以及 快速整合一套基于OAuth2协议的鉴权,授权服务中心,客户端以及遵循...

    授权服务器:Spring Boot OAuth 2.0和OpenID Connect身份提供者授权服务器

    授权服务器兼容OAuth 2.0和OpenID Connect(OIDC)的授权服务器,仅用于演示目的,可用作OAuth2 / OIDC研讨会的一部分。目标此授权服务器应... 作为开源免费提供支持学习OAuth2 / OpenID Connect的努力(自学或作为...

    xmljava系统源码-simple-oauth2:一个简单oauth2应用服务,为第三方应用提供用户登录和授权

    方便应用开发快速对接。 2. 为什么有这个项目 OAuth 2.0作为一个业界的授权代理模式,已经有广泛的应用。其在业界有很多较好的实现,无论是spring security/shiro,还是keycloak/gravitee/mitreid connect等等,都是...

    play-framework-reactivemongo-oauth2.0:这是示例应用程序,我们在其中使用了 Play-Framework 2.3.x、Scala 2.11.x、ReactiveMongo-Extensions、Cake-Patter 和 Scala Oauth 2.0

    使用 Play-Framework 2.3.x 的 Scala Oauth 2.0 在这个示例应用程序中,我们使用Oauth2.0创建带有Play-Framework 2.3.x 、 ReactiveMongo-Extensions 、 Cake-Pattern和Scala-Oauth2-Provider 的API。 我们使用 ...

    cxf+spring webservice jar包

    oauth-provider-20100527.jar opensaml-2.5.1-1.jar openws-1.4.2-1.jar relaxngDatatype-20020414.jar saaj-api-1.3.4.jar saaj-impl-1.3.19.jar serializer-2.7.1.jar slf4j-api-1.6.2.jar slf4j-jdk14-1.6.2.jar ...

    cxf(jax-ws)+spring+hibernate整合包

    1.1.jar,log4j-1.2.14.jar,mina-core-2.0.7.jar,mssqlserver2.jar,msv-core-2011.1.jar,neethi-3.0.2.jar,oauth-20100527.jar,oauth-provider-20100527.jar,opensaml-2.5.1-1.jar,openws-1.4.2-1.jar,...

    java开源包2

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包1

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包11

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包3

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包6

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包5

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包10

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包4

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包8

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包7

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包9

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    java开源包101

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

    Java资源包01

    最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就...

Global site tag (gtag.js) - Google Analytics