基於Spring Security的Oauth2授權實現方法

這篇文章主要介紹了基於Spring Security的Oauth2授權實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨着小編來一起學習學習吧

前言

經過一段時間的學習Oauth2,在網上也借鑑學習了一些大牛的經驗,推薦在學習的過程中多看幾遍阮一峯的《理解OAuth 2.0》,經過對Oauth2的多種方式的實現,個人推薦Spring Security和Oauth2的實現是相對優雅的,理由如下:

1、相對於直接實現Oauth2,減少了很多代碼量,也就減少的查找問題的成本。

2、通過調整配置文件,靈活配置Oauth相關配置。

3、通過結合路由組件(如zuul),更好的實現微服務權限控制擴展。

Oauth2概述

oauth2根據使用場景不同,分成了4種模式

  • 授權碼模式(authorization code)
  • 簡化模式(implicit)
  • 密碼模式(resource owner password credentials)
  • 客戶端模式(client credentials)

在項目中我們通常使用授權碼模式,也是四種模式中最複雜的,通常網站中經常出現的微博,qq第三方登錄,都會採用這個形式。

Oauth2授權主要由兩部分組成:

  • Authorization server:認證服務
  • Resource server:資源服務

在實際項目中以上兩個服務可以在一個服務器上,也可以分開部署。

準備階段

核心maven依賴如下

    <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 
 <dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
 </dependency>
 <dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-springsecurity4</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.security.oauth</groupId>
  <artifactId>spring-security-oauth2</artifactId>
 </dependency>
 
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
 </dependency>
 <dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
 </dependency>

token的存儲主流有三種方式,分別爲內存、redis和數據庫,在實際項目中通常使用redis和數據庫存儲。個人推薦使用mysql數據庫存儲。

初始化數據結構、索引和數據SQL語句如下:

--
-- Oauth sql -- MYSQL
--
 
Drop table if exists oauth_client_details;
create table oauth_client_details (
 client_id VARCHAR(255) PRIMARY KEY,
 resource_ids VARCHAR(255),
 client_secret VARCHAR(255),
 scope VARCHAR(255),
 authorized_grant_types VARCHAR(255),
 web_server_redirect_uri VARCHAR(255),
 authorities VARCHAR(255),
 access_token_validity INTEGER,
 refresh_token_validity INTEGER,
 additional_information TEXT,
 autoapprove VARCHAR (255) default 'false'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
Drop table if exists oauth_access_token;
create table oauth_access_token (
 token_id VARCHAR(255),
 token BLOB,
 authentication_id VARCHAR(255),
 user_name VARCHAR(255),
 client_id VARCHAR(255),
 authentication BLOB,
 refresh_token VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
Drop table if exists oauth_refresh_token;
create table oauth_refresh_token (
 token_id VARCHAR(255),
 token BLOB,
 authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
Drop table if exists oauth_code;
create table oauth_code (
 code VARCHAR(255),
 authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
 
-- Add indexes
create index token_id_index on oauth_access_token (token_id);
create index authentication_id_index on oauth_access_token (authentication_id);
create index user_name_index on oauth_access_token (user_name);
create index client_id_index on oauth_access_token (client_id);
create index refresh_token_index on oauth_access_token (refresh_token);
create index token_id_index on oauth_refresh_token (token_id);
create index code_index on oauth_code (code);
 
-- INSERT DEFAULT DATA
INSERT INTO `oauth_client_details` VALUES ('dev', '', 'dev', 'app', 'authorization_code', 'http://localhost:7777/', '', '3600', '3600', '{"country":"CN","country_code":"086"}', 'TAIJI');

核心配置

核心配置主要分爲授權應用和客戶端應用兩部分,如下:

  • 授權應用:即Oauth2授權服務,主要包括Spring Security、認證服務和資源服務兩部分配置
  • 客戶端應用:即通過授權應用進行認證的應用,多個客戶端應用間支持單點登錄

授權應用主要配置如下:

application.properties鏈接已初始化Oauth2的數據庫即可

Application啓動類,授權服務開啓配置和Spring Security配置,如下:

@SpringBootApplication
@AutoConfigureAfter(JacksonAutoConfiguration.class)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableAuthorizationServer
public class Application extends WebSecurityConfigurerAdapter {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
 
  // 啓動的時候要注意,由於我們在controller中注入了RestTemplate,所以啓動的時候需要實例化該類的一個實例
  @Autowired
  private RestTemplateBuilder builder;
 
  // 使用RestTemplateBuilder來實例化RestTemplate對象,spring默認已經注入了RestTemplateBuilder實例
  @Bean
  public RestTemplate restTemplate() {
    return builder.build();
  }
 
  @Configuration
  public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
      registry.addViewController("/login").setViewName("login");
    }
  }
 
 
  @Override
  protected void configure(HttpSecurity http) throws Exception {
 
    http.headers().frameOptions().disable();
    http.authorizeRequests()
        .antMatchers("/403").permitAll() // for test
        .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/appManager").permitAll() // for login
        .antMatchers("/image", "/js/**", "/fonts/**").permitAll() // for login
        .antMatchers("/j_spring_security_check").permitAll()
        .antMatchers("/oauth/authorize").authenticated();
    /*.anyRequest().fullyAuthenticated();*/
    http.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
        .and()
        .authorizeRequests().anyRequest().authenticated()
        .and().logout().invalidateHttpSession(true)
        .and().sessionManagement().maximumSessions(1).expiredUrl("/login?expired").sessionRegistry(sessionRegistry());
    http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    http.rememberMe().disable();
    http.httpBasic();
 
  }
 
}

資源服務開啓,如下:

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
      http.antMatcher("/me").authorizeRequests().anyRequest().authenticated();
    }
  }

OAuth2認證授權服務配置,如下:

@Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
 public static final Logger logger = LoggerFactory.getLogger(AuthorizationServerConfiguration.class);
 
 @Autowired
  private AuthenticationManager authenticationManager;
 
  @Autowired
  private DataSource dataSource;
  @Bean
  public TokenStore tokenStore() {
    return new JdbcTokenStore(dataSource);
  }
 
 
  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
 
    endpoints.authenticationManager(authenticationManager);
    endpoints.tokenStore(tokenStore());
    // 配置TokenServices參數
    DefaultTokenServices tokenServices = new DefaultTokenServices();
    tokenServices.setTokenStore(endpoints.getTokenStore());
    tokenServices.setSupportRefreshToken(false);
    tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
    tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
    tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.MINUTES.toSeconds(10)); //分鐘
    endpoints.tokenServices(tokenServices);
  }
 
 
  @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.checkTokenAccess("isAuthenticated()");
    oauthServer.allowFormAuthenticationForClients();
  }
 
  @Bean
  public ClientDetailsService clientDetails() {
    return new JdbcClientDetailsService(dataSource);
  }
 
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
      clients.withClientDetails(clientDetails());
    /*    
    *    基於內存配置項
    *    clients.inMemory()
        .withClient("community")
        .secret("community")
        .authorizedGrantTypes("authorization_code").redirectUris("http://tech.taiji.com.cn/")
        .scopes("app").and() .withClient("dev")
        .secret("dev")
        .authorizedGrantTypes("authorization_code").redirectUris("http://localhost:7777/")
        .scopes("app");*/
  }
}

客戶端應用主要配置如下:

application.properties中Oauth2配置,如下

security.oauth2.client.clientId=dev
security.oauth2.client.clientSecret=dev
security.oauth2.client.accessTokenUri=http://localhost:9999/oauth/token
security.oauth2.client.userAuthorizationUri=http://localhost:9999/oauth/authorize
security.oauth2.resource.loadBalanced=true
security.oauth2.resource.userInfoUri=http://localhost:9999/me
security.oauth2.resource.logout.url=http://localhost:9999/revoke-token
security.oauth2.default.roleName=ROLE_USER

Oauth2Config配置,授權Oauth2Sso配置和Spring Security配置,如下:

@Configuration
@EnableOAuth2Sso
public class Oauth2Config extends WebSecurityConfigurerAdapter{
 @Autowired
 CustomSsoLogoutHandler customSsoLogoutHandler;
 
 @Autowired
 OAuth2ClientContext oauth2ClientContext;
 
 @Bean
 public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
   StrictHttpFirewall firewall = new StrictHttpFirewall();
   firewall.setAllowUrlEncodedSlash(true);
   firewall.setAllowSemicolon(true);
   return firewall;
 }
 
 @Bean
 @ConfigurationProperties("security.oauth2.client")
 public AuthorizationCodeResourceDetails taiji() {
 return new AuthorizationCodeResourceDetails();
 }
 
 @Bean
 public CommunitySuccessHandler customSuccessHandler() {
 CommunitySuccessHandler customSuccessHandler = new CommunitySuccessHandler();
 customSuccessHandler.setDefaultTargetUrl("/");
 return customSuccessHandler;
 }
 
 @Bean
 public CustomFailureHandler customFailureHandler() {
 CustomFailureHandler customFailureHandler = new CustomFailureHandler();
 customFailureHandler.setDefaultFailureUrl("/index");
 return customFailureHandler;
 }
 
 @Bean
 @Primary
 @ConfigurationProperties("security.oauth2.resource")
 public ResourceServerProperties taijiOauthorResource() {
 return new ResourceServerProperties();
 }
 
 @Bean
 @Override
 public AuthenticationManager authenticationManagerBean() throws Exception {
 List<AuthenticationProvider> authenticationProviderList = new ArrayList<AuthenticationProvider>();
 authenticationProviderList.add(customAuthenticationProvider());
 AuthenticationManager authenticationManager = new ProviderManager(authenticationProviderList);
 return authenticationManager;
 }
 
 @Autowired
 public TaijiUserDetailServiceImpl userDetailsService;
 
 @Bean
 public TaijiAuthenticationProvider customAuthenticationProvider() {
 TaijiAuthenticationProvider customAuthenticationProvider = new TaijiAuthenticationProvider();
 customAuthenticationProvider.setUserDetailsService(userDetailsService);
 return customAuthenticationProvider;
 }
 
 
 @Autowired
 private MenuService menuService;
 @Autowired
 private RoleService roleService;
 @Bean
 public TaijiSecurityMetadataSource taijiSecurityMetadataSource() {
 TaijiSecurityMetadataSource fisMetadataSource = new TaijiSecurityMetadataSource();
// fisMetadataSource.setMenuService(menuService);
 fisMetadataSource.setRoleService(roleService);
 return fisMetadataSource;
 }
 
 @Autowired
 private CommunityAccessDecisionManager accessDecisionManager;
 @Bean
 public CommunityFilterSecurityInterceptor communityfiltersecurityinterceptor() throws Exception {
 CommunityFilterSecurityInterceptor taijifiltersecurityinterceptor = new CommunityFilterSecurityInterceptor();
 taijifiltersecurityinterceptor.setFisMetadataSource(taijiSecurityMetadataSource());
 taijifiltersecurityinterceptor.setAccessDecisionManager(accessDecisionManager);
 taijifiltersecurityinterceptor.setAuthenticationManager(authenticationManagerBean());
 return taijifiltersecurityinterceptor;
 }
 
 
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 http.authorizeRequests()
//     .antMatchers("/").permitAll() 
//  .antMatchers("/login").permitAll() // 
//  .antMatchers("/image").permitAll() // 
//  .antMatchers("/upload/*").permitAll() // for
//  .antMatchers("/common/**").permitAll() // for 
//  .antMatchers("/community/**").permitAll()
  
//     .antMatchers("/").anonymous()
     .antMatchers("/personal/**").authenticated()
     .antMatchers("/notify/**").authenticated()
     .antMatchers("/admin/**").authenticated()
     .antMatchers("/manage/**").authenticated()
     .antMatchers("/**/personal/**").authenticated()
     .antMatchers("/user/**").authenticated()
  .anyRequest()
  .permitAll()
//  .authenticated()
  .and()
  .logout()
  .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
  .addLogoutHandler(customSsoLogoutHandler)
  .deleteCookies("JSESSIONID").invalidateHttpSession(true)
  .and()
  .csrf().disable()
  //.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
  //.and()
  .addFilterBefore(loginFilter(), BasicAuthenticationFilter.class)
  .addFilterAfter(communityfiltersecurityinterceptor(), FilterSecurityInterceptor.class);///TaijiSecurity權限控制
 }
 
 @Override
 public void configure(WebSecurity web) throws Exception {
 // 解決靜態資源被攔截的問題
 web.ignoring().antMatchers("/theme/**")
  .antMatchers("/community/**")
  .antMatchers("/common/**")
  .antMatchers("/upload/*");
 web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
 }
 
 
 public OAuth2ClientAuthenticationProcessingFilter loginFilter() throws Exception {
 OAuth2ClientAuthenticationProcessingFilter ff = new OAuth2ClientAuthenticationProcessingFilter("/login");
 OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(taiji(),oauth2ClientContext);
 ff.setRestTemplate(restTemplate);
 UserInfoTokenServices tokenServices = new UserInfoTokenServices(taijiOauthorResource().getUserInfoUri(), taiji().getClientId());
 tokenServices.setRestTemplate(restTemplate);
 ff.setTokenServices(tokenServices);
 ff.setAuthenticationSuccessHandler(customSuccessHandler());
    ff.setAuthenticationFailureHandler(customFailureHandler());
 return ff;
 }
}

授權成功回調類,認證成功用戶落地,如下:

public class CommunitySuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
 
 protected final Log logger = LogFactory.getLog(this.getClass());
 
 private RequestCache requestCache = new HttpSessionRequestCache();
 @Autowired
 private UserService userService;
 @Autowired
 private RoleService roleService;
 @Inject
 AuthenticationManager authenticationManager;
 @Value("${security.oauth2.default.roleName}")
 private String defaultRole;
 @Inject
 TaijiOperationLogService taijiOperationLogService;
 
 @Inject
 CommunityConfiguration communityConfiguration;
 
 @Inject
 private ObjectMapper objectMapper;
 
 @ScoreRule(code="login_score")
 @Override
 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
  Authentication authentication) throws ServletException, IOException {
 // 存放authentication到SecurityContextHolder
 SecurityContextHolder.getContext().setAuthentication(authentication);
 HttpSession session = request.getSession(true);
 // 在session中存放security context,方便同一個session中控制用戶的其他操作
 session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
 OAuth2Authentication oauth2Authentication = (OAuth2Authentication) authentication;
 Object details = oauth2Authentication.getUserAuthentication().getDetails();
 UserDto user = saveUser((Map) details);//用戶落地
 Collection<GrantedAuthority> obtionedGrantedAuthorities = obtionGrantedAuthorities(user);
 UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken(
  new User(user.getLoginName(), "", true, true, true, true, obtionedGrantedAuthorities), 
  authentication.getCredentials(), obtionedGrantedAuthorities);
 
 newToken.setDetails(details);
 Object oath2details=oauth2Authentication.getDetails();
 oauth2Authentication = new OAuth2Authentication(oauth2Authentication.getOAuth2Request(), newToken);
 oauth2Authentication.setDetails(oath2details);
 oauth2Authentication.setAuthenticated(true);
 SecurityContextHolder.getContext().setAuthentication(oauth2Authentication);
 
 LogUtil.log2database(taijiOperationLogService, request, user.getLoginName(), "user", "", "", "user_login", "登錄", "onAuthenticationSuccess","");
 session.setAttribute("user", user);
 Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) authentication.getAuthorities();
 
 SavedRequest savedRequest = requestCache.getRequest(request, response);
 if (savedRequest == null) {
  super.onAuthenticationSuccess(request, response, authentication);
  return;
 }
 String targetUrlParameter = getTargetUrlParameter();
 if (isAlwaysUseDefaultTargetUrl()
  || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
  requestCache.removeRequest(request, response);
  super.onAuthenticationSuccess(request, response, authentication);
  return;
 }
 clearAuthenticationAttributes(request);
 // Use the DefaultSavedRequest URL
 String targetUrl = savedRequest.getRedirectUrl();
// logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
 
 logger.debug("Redirecting to last savedRequest Url: " + targetUrl);
 getRedirectStrategy().sendRedirect(request, response, targetUrl);
// getRedirectStrategy().sendRedirect(request, response, this.getDefaultTargetUrl());
 }
 
 public void setRequestCache(RequestCache requestCache) {
 this.requestCache = requestCache;
 }
 
 //用戶落地
 private UserDto saveUser(Map userInfo) {
 UserDto dto=null;
 try {
  String json = objectMapper.writeValueAsString(userInfo);
  dto = objectMapper.readValue(json,UserDto.class);
 } catch (JsonProcessingException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 
 UserDto user=userService.findByLoginName(dto.getLoginName());
 if(user!=null) {
  return user;
 }
 Set<RoleDto> roles= new HashSet<RoleDto>();
 RoleDto role = roleService.findByRoleName(defaultRole);
 roles.add(role);
 dto.setRoles(roles);
 List<UserDto> list = new ArrayList<UserDto>();
 list.add(dto);
 dto.generateTokenForCommunity(communityConfiguration.getControllerSalt());
 String id =userService.saveUserWithRole(dto,communityConfiguration.getControllerSalt());
 dto.setId(id);
 return dto;
 }
 
 /**
   * Map轉成實體對象
   *
   * @param map  map實體對象包含屬性
   * @param clazz 實體對象類型
   * @return
   */
  public static <T> T map2Object(Map<String, Object> map, Class<T> clazz) {
    if (map == null) {
      return null;
    }
    T obj = null;
    try {
      obj = clazz.newInstance();
 
      Field[] fields = obj.getClass().getDeclaredFields();
      for (Field field : fields) {
        int mod = field.getModifiers();
        if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
          continue;
        }
        field.setAccessible(true);
        String filedTypeName = field.getType().getName();
        if (filedTypeName.equalsIgnoreCase("java.util.date")) {
          String datetimestamp = String.valueOf(map.get(field.getName()));
          if (datetimestamp.equalsIgnoreCase("null")) {
            field.set(obj, null);
          } else {
            field.set(obj, new Date(Long.parseLong(datetimestamp)));
          }
        } else {
         String v = map.get(field.getName()).toString();
          field.set(obj, map.get(field.getName()));
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return obj;
  }
 
 
 
 // 取得用戶的權限
 private Collection<GrantedAuthority> obtionGrantedAuthorities(UserDto users) {
 Collection<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
 // 獲取用戶角色
 Set<RoleDto> roles = users.getRoles();
 if (null != roles && !roles.isEmpty())
  for (RoleDto role : roles) {
 authSet.add(new SimpleGrantedAuthority(role.getId()));
  }
 return authSet;
 }
}

客戶端應用,單點登錄方法,如下:

@RequestMapping(value = "/loadToken", method = { RequestMethod.GET })
 public void loadToken(Model model,HttpServletResponse response,@RequestParam(value = "clientId", required = false) String clientId) {
 String token = "";
 RequestAttributes ra = RequestContextHolder.getRequestAttributes();
 ServletRequestAttributes sra = (ServletRequestAttributes) ra;
 HttpServletRequest request = sra.getRequest();
 HttpSession session = request.getSession();
 if (session.getAttribute("SPRING_SECURITY_CONTEXT") != null) {
  SecurityContext securityContext = (SecurityContext)session.getAttribute("SPRING_SECURITY_CONTEXT");
  Authentication authentication = securityContext.getAuthentication();
  OAuth2AuthenticationDetails OAuth2AuthenticationDetails = (OAuth2AuthenticationDetails) authentication.getDetails();
  token = OAuth2AuthenticationDetails.getTokenValue();
 }
 try {
  String url = "http://localhost:9999/rediect?clientId=dev&token="+token;
  response.sendRedirect(url);
 } catch (IOException e) {
  e.printStackTrace();
 }
 }

服務端應用,單點登錄方法,如下:

@RequestMapping("/rediect")
 public String rediect(HttpServletResponse responsel, String clientId, String token) {
 OAuth2Authentication authentication = tokenStore.readAuthentication(token);
 if (authentication == null) {
  throw new InvalidTokenException("Invalid access token: " + token);
 }
 OAuth2Request request = authentication.getOAuth2Request();
 Map map = new HashMap();
 map.put("code", request.getRequestParameters().get("code"));
 map.put("grant_type", request.getRequestParameters().get("grant_type"));
 map.put("response_type", request.getRequestParameters().get("response_type"));
 //TODO 需要查詢一下要跳轉的Client_id配置的回調地址
 map.put("redirect_uri", "http://127.0.0.1:8888");
 map.put("client_id", clientId);
 map.put("state", request.getRequestParameters().get("state"));
 request = new OAuth2Request(map, clientId, request.getAuthorities(), request.isApproved(), request.getScope(),
  request.getResourceIds(), map.get("redirect_uri").toString(), request.getResponseTypes(),request.getExtensions()); // 模擬用戶登錄
 Authentication t = tokenStore.readAuthentication(token);
 OAuth2Authentication auth = new OAuth2Authentication(request, t);
 OAuth2AccessToken new_token = defaultTokenServices.createAccessToken(auth);
 return "redirect:/user_info?access_token=" + new_token.getValue();
 }
@RequestMapping({ "/user_info" })
 public void user(String access_token,HttpServletResponse response) {
 OAuth2Authentication auth=tokenStore.readAuthentication(access_token);
 OAuth2Request request=auth.getOAuth2Request();
  Map<String, String> map = new LinkedHashMap<>();
  map.put("loginName", auth.getUserAuthentication().getName());
  map.put("password", auth.getUserAuthentication().getName());
  map.put("id", auth.getUserAuthentication().getName());
  try {
 response.sendRedirect(request.getRedirectUri()+"?name="+auth.getUserAuthentication().getName());
 } catch (IOException e) {
 e.printStackTrace();
 }
}

個人總結

Oauth2的設計相對複雜,需要深入學習多看源碼才能瞭解內部的一些規則,如數據token的存儲是用的實體序列化後內容,需要反序列才能在項目是使用,也許是爲了安全,但在學習過程需要提前掌握,還有在token的過期時間不能爲0,通常來講過期時間爲0代表長期有效,但在Oauth2中則報錯,這些坑需要一點點探索。

通過集成Spring Security和Oauth2較大的提供的開發的效率,也提供的代碼的靈活性和可用性。但封裝的核心類需要大家都瞭解一下,通讀下代碼,以便在項目中可隨時獲取需要的參數。

示例代碼

以下是個人的一套代碼,供參考。

基於Spring Cloud的微服務框架集成Oauth2的代碼示例

Oauth2數據結構,如下:

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章