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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM