zoukankan      html  css  js  c++  java
  • 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位随机英数字。 

    Java代码  收藏代码
    1. @Configuration  
    2. @EnableAuthorizationServer  
    3. public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {  
    4.   
    5.     @Bean  
    6.     protected AuthorizationCodeServices authorizationCodeServices() {  
    7.         return new CustomJdbcAuthorizationCodeServices(dataSource());  
    8.     }  
    9.   
    10. }  
    11.   
    12. public class CustomJdbcAuthorizationCodeServices extends JdbcAuthorizationCodeServices {  
    13.   
    14.     private RandomValueStringGenerator generator = new RandomValueStringGenerator();  
    15.       
    16.     public CustomJdbcAuthorizationCodeServices(DataSource dataSource) {  
    17.         super(dataSource);  
    18.         this.generator = new RandomValueStringGenerator(32);  
    19.     }  
    20.       
    21.     public String createAuthorizationCode(OAuth2Authentication authentication) {  
    22.         String code = this.generator.generate();  
    23.         store(code, authentication);  
    24.         return code;  
    25.     }  
    26.   
    27. }  



    效果如下: 


    (2)自定义生成令牌 

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

    Java代码  收藏代码
    1. @Configuration  
    2. @EnableAuthorizationServer  
    3. public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {  
    4.   
    5.     @Bean  
    6.     public TokenEnhancer tokenEnhancer() {  
    7.         return new CustomTokenEnhancer();  
    8.     }  
    9.   
    10. }  
    Java代码  收藏代码
    1. public class CustomTokenEnhancer implements TokenEnhancer {  
    2.   
    3.     @Override  
    4.     public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {  
    5.         if (accessToken instanceof DefaultOAuth2AccessToken) {  
    6.             DefaultOAuth2AccessToken token = ((DefaultOAuth2AccessToken) accessToken);  
    7.             token.setValue(getNewToken());  
    8.               
    9.             OAuth2RefreshToken refreshToken = token.getRefreshToken();  
    10.             if (refreshToken instanceof DefaultOAuth2RefreshToken) {  
    11.                 token.setRefreshToken(new DefaultOAuth2RefreshToken(getNewToken()));  
    12.             }  
    13.               
    14.             Map<String, Object> additionalInformation = new HashMap<String, Object>();  
    15.             additionalInformation.put("client_id", authentication.getOAuth2Request().getClientId());  
    16.             token.setAdditionalInformation(additionalInformation);  
    17.               
    18.             return token;  
    19.         }  
    20.         return accessToken;  
    21.     }  
    22.       
    23.     private String getNewToken() {  
    24.         return UUID.randomUUID().toString().replace("-", "");  
    25.     }  
    26.   
    27. }  



    效果如下: 


    (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: 

    Java代码  收藏代码
    1. @Configuration  
    2. @EnableAuthorizationServer  
    3. public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {  
    4.     @Autowired  
    5.     private AuthorizationEndpoint authorizationEndpoint;  
    6.   
    7.     @PostConstruct  
    8.     public void init() {  
    9.         authorizationEndpoint.setUserApprovalPage("forward:/oauth/my_approval_page");  
    10.         authorizationEndpoint.setErrorPage("forward:/oauth/my_error_page");  
    11.     }  
    12. }  



    页面实现: 

    Java代码  收藏代码
    1. @Controller  
    2. @SessionAttributes({ "authorizationRequest" })  
    3. public class OAuthController {  
    4.   
    5.     @RequestMapping({ "/oauth/my_approval_page" })  
    6.     public String getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {  
    7.         @SuppressWarnings("unchecked")  
    8.         Map<String, String> scopes = (Map<String, String>) (model.containsKey("scopes") ? model.get("scopes") : request.getAttribute("scopes"));  
    9.         List<String> scopeList = new ArrayList<String>();  
    10.         for (String scope : scopes.keySet()) {  
    11.             scopeList.add(scope);  
    12.         }  
    13.         model.put("scopeList", scopeList);  
    14.         return "oauth_approval";  
    15.     }  
    16.   
    17.     @RequestMapping({ "/oauth/my_error_page" })  
    18.     public String handleError(Map<String, Object> model, HttpServletRequest request) {  
    19.         Object error = request.getAttribute("error");  
    20.         String errorSummary;  
    21.         if (error instanceof OAuth2Exception) {  
    22.             OAuth2Exception oauthError = (OAuth2Exception) error;  
    23.             errorSummary = HtmlUtils.htmlEscape(oauthError.getSummary());  
    24.         } else {  
    25.             errorSummary = "Unknown error";  
    26.         }  
    27.         model.put("errorSummary", errorSummary);  
    28.         return "oauth_error";  
    29.     }  
    30. }  



    /src/main/resources/templates/oauth_approval.html 

    Html代码  收藏代码
    1. <!DOCTYPE HTML>  
    2. <html xmlns="http://www.w3.org/1999/xhtml"  
    3.       xmlns:th="http://www.thymeleaf.org">  
    4. <head>  
    5.   <title>approval</title>  
    6.   <meta charset="utf-8"/>  
    7. </head>  
    8. <body>  
    9.   <div class="container">  
    10.     <div class="row">  
    11.       <div class="col-md-12 well">  
    12.         <h3>授权页</h3>  
    13.         应用名 : <span th:text="${session.authorizationRequest.clientId}">clientId</span>  
    14.   
    15.         <form id='confirmationForm' name='confirmationForm' th:action="@{/oauth/authorize}" method='post'>  
    16.             <input name='user_oauth_approval' value='true' type='hidden' />  
    17.             <input th:name="${s}" value="true" type="hidden" th:each="s : ${scopeList}" />  
    18.             <input name='authorize' value='授权' type='submit' />  
    19.         </form>  
    20.       </div>  
    21.     </div>  
    22.   </div>  
    23. </body>  
    24. </html>  



    /src/main/resources/templates/oauth_error.html 

    Html代码  收藏代码
    1. <!DOCTYPE HTML>  
    2. <html xmlns="http://www.w3.org/1999/xhtml"  
    3.       xmlns:th="http://www.thymeleaf.org">  
    4. <head>  
    5.   <title>error</title>  
    6.   <meta charset="utf-8"/>  
    7. </head>  
    8. <body>  
    9.   <div class="container">  
    10.     <div class="row">  
    11.       <div class="col-md-12 well">  
    12.         <h3>错误</h3>  
    13.         <style="color:red;">出错了!不能继续授权操作!</p>  
    14.         <th:utext="${errorSummary}">errorSummary  
    15.       </div>  
    16.     </div>  
    17.   </div>  
    18. </body>  
    19. </html>  



    效果如下: 
     


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

    创建用户表 

    Sql代码  收藏代码
    1. CREATE TABLE account  
    2. (  
    3.   id serial NOT NULL,  
    4.   user_name character varying(50),  
    5.   email character varying(255),  
    6.   password character varying(512),  
    7.   role_string character varying(50),  
    8.   CONSTRAINT account_pkey PRIMARY KEY (id)  
    9. );  
    10.   
    11. INSERT INTO account(user_name, email, password, role_string)  
    12.     VALUES ('user', 'user@sample.com', '123', 'ROLE_USER');  



    配置SpringSecurity 

    Java代码  收藏代码
    1. @Configuration  
    2. @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)  
    3. @EnableWebSecurity  
    4. static class SecurityConfig extends WebSecurityConfigurerAdapter {  
    5.     @Override  
    6.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
    7.         auth.authenticationProvider(authenticationProvider);  
    8.     }  
    9.   
    10.     @Override  
    11.     protected void configure(HttpSecurity http) throws Exception {  
    12.       http.csrf().disable();  
    13.   
    14.       http.antMatcher("/oauth/**")  
    15.         .authorizeRequests()  
    16.           .antMatchers("/oauth/index").permitAll()  
    17.           .antMatchers("/oauth/token").permitAll()  
    18.           .antMatchers("/oauth/check_token").permitAll()  
    19.           .antMatchers("/oauth/confirm_access").permitAll()  
    20.           .antMatchers("/oauth/error").permitAll()  
    21.           .antMatchers("/oauth/my_approval_page").permitAll()  
    22.           .antMatchers("/oauth/my_error_page").permitAll()  
    23.           .anyRequest().authenticated()  
    24.         .and()  
    25.           .formLogin()  
    26.           .loginPage("/oauth/index")  
    27.           .loginProcessingUrl("/oauth/login");  
    28.     }  
    29.     @Autowired  
    30.     private CustomAuthenticationProvider authenticationProvider;  
    31. }  
    Java代码  收藏代码
    1. @Configuration  
    2. @MapperScan("com.rensanning")  
    3. @EnableTransactionManagement(proxyTargetClass = true)  
    4. static class RepositoryConfig {  
    5. }  



    用户登录处理部分 

    Java代码  收藏代码
    1. @Component  
    2. public class CustomAuthenticationProvider implements AuthenticationProvider {  
    3.   
    4.   @Autowired  
    5.   private AccountService accountService;  
    6.   
    7.   @Override  
    8.   public Authentication authenticate(Authentication authentication) throws AuthenticationException {  
    9.   
    10.     String name = authentication.getName();  
    11.     String password = authentication.getCredentials().toString();  
    12.   
    13.     Account account = accountService.authUser(name, password);  
    14.     if (account == null) {  
    15.       throw new AuthenticationCredentialsNotFoundException("Account is not found.");  
    16.     }  
    17.   
    18.     List<GrantedAuthority> grantedAuths = AuthorityUtils.createAuthorityList(account.getRoleString());  
    19.     return new UsernamePasswordAuthenticationToken(name, password, grantedAuths);  
    20.   }  
    21.   
    22.   @Override  
    23.   public boolean supports(Class<?> authentication) {  
    24.     return authentication.equals(UsernamePasswordAuthenticationToken.class);  
    25.   }  
    26. }  
    Java代码  收藏代码
    1. @Service  
    2. public class AccountService {  
    3.   
    4.   @Autowired  
    5.   private AccountRepository accountRepository;  
    6.   
    7.   public Account authUser(String userName, String password) {  
    8.     Account u = accountRepository.findByUserName(userName);  
    9.     if (u == null) {  
    10.       return null;  
    11.     }  
    12.     if (!u.getPassword().equals(password)) {  
    13.       return null;  
    14.     }  
    15.     return u;  
    16.   }  
    17.   
    18. }  
    Java代码  收藏代码
    1. public interface AccountRepository {  
    2.   @Select("select id, user_name as userName, email, password, role_string as roleString from account where user_name=#{user_name}")  
    3.   Account findByUserName(String userName);  
    4. }  
    Java代码  收藏代码
    1. @SuppressWarnings("serial")  
    2. public class Account implements Serializable {  
    3.   private Integer id;  
    4.   private String userName;  
    5.   private String email;  
    6.   private String password;  
    7.   private String roleString;  
    8.   // ...setter/getter  
    9. }  


     

    完成的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

    1 
    1 
    分享到:  
    评论
    3 楼 IT小新 2017-10-27  
    求该例子得示例代码呗,谢谢了
    2 楼 xu_yuan 2017-10-24  
    LS少写了thymeleaf的配置,如果不加的话,是不能识别thymeleaf语法的html文件的。会导致controller虽然返回了oauth_approval,但是却报错error 找不到mapping

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


    application.yml 需要加入以下配置
    Yml代码  收藏代码
    1. spring:  
    2.   thymeleaf:  
    3.     prefix: classpath:/templates/ # 模板路径  
    1 楼 ihanfeng 2017-08-31  
    本例有没有相关代码实例,根据你上面的配置没搞成功,登录后又返回登录页面。
     
     
     
     
     
    转自:https://www.iteye.com/blog/rensanning-2386553
  • 相关阅读:
    Windows API 之 Windows Service
    揭开Socket编程的面纱 (一)
    开发中“错误: 意外地调用了方法或属性访问。” 和 第一行错误 的IE 两个问题( JQ 进行转义字符 , 分页JS 调用 时参数问题。)
    结合MSDN理解windows service 服务安装的三个类。
    VFW基础知识(一些定义性质的。从CSDN中得到的。)
    初次接触WIN FORM,深入事件、委托、方法 ,深入看不到的C#探索。
    C#: +(特性 ) + Attitude C#(类)前面或者(方法)前面 (中括号)定义
    VFW系列教程经典
    依赖注入
    Windows Service:SC 和 InstallUtil 区别
  • 原文地址:https://www.cnblogs.com/panchanggui/p/12275578.html
Copyright © 2011-2022 走看看