如何使用 spring security 和 spring boot 对 Google 用户进行身份验证,将 mongoDB 作为存储库?
Posted
技术标签:
【中文标题】如何使用 spring security 和 spring boot 对 Google 用户进行身份验证,将 mongoDB 作为存储库?【英文标题】:How to authenticate Google users by using spring security and spring boot, having mongoDB as repository? 【发布时间】:2016-03-21 03:37:28 【问题描述】:我是春天的新手。我正在使用 spring boot 以利用一些预定义的配置。好像很有用。
两个多星期以来,我一直坚持使用 spring security 创建身份验证和授权。我想使用 Google 用户进行身份验证。我使用 MongoDB 作为数据存储。
这是我与 Google 用户联系的代码,
1. SocialConnectionConfiguration.java
package com.example.social;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.social.google.connect.GoogleConnectionFactory;
@Configuration
public class SocialConnectionConfiguration
// Google Application Credentials
private static final String GoogleClientID = "<clientID>";
private static final String GoogleClientSecret = "<clientSecret>";
@Bean
public GoogleConnectionFactory getGoogleConnectionFactory()
GoogleConnectionFactory connectionFactory =
new GoogleConnectionFactory(GoogleClientID, GoogleClientSecret);
return connectionFactory;
2。 SocialConnectionConfiguration.java
package com.example.social;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.social.google.connect.GoogleConnectionFactory;
@Configuration
public class SocialConnectConfiguration
@Autowired
GoogleConnectionFactory gplusConnectionFactory;
@Bean
public GoogleAPI getGoogleAPI()
GoogleAPI googleAPI = new GoogleAPI(gplusConnectionFactory);
return googleAPI;
3. GoogleAPI.java
package com.example.social;
import org.springframework.social.connect.Connection;
import org.springframework.social.google.api.Google;
import org.springframework.social.google.connect.GoogleConnectionFactory;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.GrantType;
import org.springframework.social.oauth2.OAuth2Parameters;
public class GoogleAPI
private GoogleConnectionFactory GplusConnectionFactory;
private Google google;
private static final String REDIRECT_URI = "http://localhost:8080/google_response";
public Google getGoogle()
return google;
public GoogleAPI(GoogleConnectionFactory GplusConnectionFactory)
this.GplusConnectionFactory = GplusConnectionFactory;
public String getRedirectURI()
OAuth2Parameters params = new OAuth2Parameters();
params.setRedirectUri(REDIRECT_URI);
params.setScope("profile");
params.setScope("openid");
params.setScope("email");
String authorizeUrl = GplusConnectionFactory.getOAuthOperations().buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
return authorizeUrl;
public Google establishFacebookConnection(String accessToken)
AccessGrant accessGrant = GplusConnectionFactory.getOAuthOperations().exchangeForAccess(accessToken,REDIRECT_URI, null);
Connection<Google> connection = GplusConnectionFactory.createConnection(accessGrant);
google = connection.getApi();
return google;
public boolean isAuthorized()
if(google != null)
return google.isAuthorized();
return false;
以上三个文件用于连接google。但是如何使用相同的代码进行身份验证。
正如我经历过的this tutorial (Follow Tutorial-1,2,3)。我发现了一些我们应该拥有的信息(如下),
所以我创建了以下类:
-
实体模型
数据存储库
商务服务
用户详细信息服务
身份验证提供程序
安全配置
1.a) 实体模型(UserAccount.java)
package com.example.model;
import java.util.Set;
import javax.validation.constraints.NotNull;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection="user_account")
public class UserAccount
@Id
private ObjectId id;
private String firstName;
@Indexed
private String lastName;
private Integer age;
@Indexed
@NotNull
private final String username;
@NotNull
private String password;
@NotNull
private boolean enabled = true;
@NotNull
private boolean credentialsexpired = false;
@NotNull
private boolean expired = false;
@NotNull
private boolean locked = false;
private Set<Role> roles;
@PersistenceConstructor
public UserAccount(String username, String firstName, String lastName, Integer age)
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
public ObjectId getId()
return id;
public String getFirstName()
return firstName;
public void setFirstName(String firstName)
this.firstName = firstName;
public String getLastName()
return lastName;
public void setLastName(String lastName)
this.lastName = lastName;
public Integer getAge()
return age;
public void setAge(Integer age)
this.age = age;
public String getUsername()
return username;
public String getPassword()
return password;
public void setPassword(String password)
this.password = password;
public boolean isEnabled()
return enabled;
public void setEnabled(boolean enabled)
this.enabled = enabled;
public boolean isCredentialsexpired()
return credentialsexpired;
public void setCredentialsexpired(boolean credentialsexpired)
this.credentialsexpired = credentialsexpired;
public boolean isExpired()
return expired;
public void setExpired(boolean expired)
this.expired = expired;
public boolean isLocked()
return locked;
public void setLocked(boolean locked)
this.locked = locked;
public Set<Role> getRoles()
return roles;
public void setRoles(Set<Role> roles)
this.roles = roles;
@Override
public String toString()
return "[" + this.getId() +
" : " + this.getUsername() +
" : " + this.firstName +
" : " + this.getLastName() +
" : " + this.getAge().toString()+"]";
1.b) 实体模型(Role.java)
package com.example.model;
import javax.validation.constraints.NotNull;
public class Role
private static final String ADMIN = "ADMIN";
private static final String MANAGER = "MANAGER";
private static final String USER = "USER";
@NotNull
private String code;
@NotNull
private String label;
public Role()
public Role(String code)
this.code = code;
assignRole(code);
private void assignRole(String code)
if(code.equals("1"))
this.label = ADMIN;
else if(code.equals("2"))
this.label = MANAGER;
else if(code.equals("3"))
this.label = USER;
public String getCode()
return code;
public void setCode(String code)
this.code = code;
public String getLabel()
return label;
public void setLabel(String label)
this.label = label;
2。数据存储库(UserAccountRepository.java)
package com.example.repository;
import java.io.Serializable;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.example.model.UserAccount;
@Repository
public interface UserAccountRepository extends MongoRepository<UserAccount, Serializable>
public UserAccount findById(ObjectId id);
public UserAccount findByUsername(String username);
3.a) UserDteailsService(UserAccountDetailsService.java)
package com.example.secutiry;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.example.model.Role;
import com.example.model.UserAccount;
import com.example.service.UserAccountService;
@Service
public class UserAccountDetailsService implements UserDetailsService
@Autowired
private UserAccountService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
UserAccount user = userService.findByUsername(username);
if(user == null)
throw new UsernameNotFoundException("Given user name doesn't match !");
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
for (Role role : user.getRoles())
grantedAuthorities.add(new SimpleGrantedAuthority(role.getLabel()));
User userDetails = new User(user.getUsername(),
user.getPassword(),user.isEnabled(),
user.isExpired(),user.isCredentialsexpired(),
user.isLocked(), grantedAuthorities);
return userDetails;
3.b) UserDteailsService(UserAccountService.java)
package com.example.service;
import java.io.Serializable;
import java.util.List;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import com.example.model.UserAccount;
import com.example.repository.UserAccountRepository;
@Service
public class UserAccountService implements UserAccountRepository
@Autowired
private UserAccountRepository repository;
@Override
public <S extends UserAccount> List<S> save(Iterable<S> entites)
// TODO Auto-generated method stub
return null;
@Override
public List<UserAccount> findAll()
// TODO Auto-generated method stub
return null;
@Override
public List<UserAccount> findAll(Sort sort)
// TODO Auto-generated method stub
return null;
@Override
public <S extends UserAccount> S insert(S entity)
// TODO Auto-generated method stub
return null;
@Override
public <S extends UserAccount> List<S> insert(Iterable<S> entities)
// TODO Auto-generated method stub
return null;
@Override
public Page<UserAccount> findAll(Pageable pageable)
// TODO Auto-generated method stub
return null;
@Override
public <S extends UserAccount> S save(S entity)
repository.save(entity);
return null;
@Override
public UserAccount findOne(Serializable id)
// TODO Auto-generated method stub
return null;
@Override
public boolean exists(Serializable id)
// TODO Auto-generated method stub
return false;
@Override
public Iterable<UserAccount> findAll(Iterable<Serializable> ids)
// TODO Auto-generated method stub
return null;
@Override
public long count()
// TODO Auto-generated method stub
return 0;
@Override
public void delete(Serializable id)
// TODO Auto-generated method stub
@Override
public void delete(UserAccount entity)
// TODO Auto-generated method stub
@Override
public void delete(Iterable<? extends UserAccount> entities)
// TODO Auto-generated method stub
@Override
public void deleteAll()
// TODO Auto-generated method stub
@Override
public UserAccount findById(ObjectId id)
UserAccount user = repository.findById(id);
return user;
@Override
public UserAccount findByUsername(String username)
UserAccount user = repository.findByUsername(username);
return user;
4. AuthenticationProvider (UserAccountAuthenticationProvider.java)
package com.example.secutiry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class UserAccountAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
@Autowired
private UserAccountDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken token)
throws AuthenticationException
if(token.getCredentials() == null
|| userDetails.getPassword() == null)
throw new BadCredentialsException("Credentials may not be Empty!");
if(!passwordEncoder.matches(token.getCredentials().toString(),
userDetails.getPassword()))
throw new BadCredentialsException("Invalid Credentials !");
@Override
protected UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return userDetails;
5.安全配置(SecurityConfiguration.java)
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.example.secutiry.UserAccountAuthenticationProvider;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration
@Autowired
private UserAccountAuthenticationProvider userAccountAuthenticationProvider;
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
auth.authenticationProvider(userAccountAuthenticationProvider);
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter
extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http
.antMatcher("/**")
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
所以现在,如果我单独使用 Google 连接代码,我可以连接到 google。没关系,但是如何使用 Google 连接代码进行身份验证?
如果我的代码有误,请纠正我,如果我想包含或排除任何行或文件,请指导我,因为我是 spring 新手。
提前致谢
【问题讨论】:
【参考方案1】:为什么要在自己的 UserDetailsService 实现中再次检查密码?
if(token.getCredentials() == null
|| userDetails.getPassword() == null)
throw new BadCredentialsException("Credentials may not be Empty!");
if(!passwordEncoder.matches(token.getCredentials().toString(),
userDetails.getPassword()))
throw new BadCredentialsException("Invalid Credentials !");
密码检查仅由谷歌身份提供者完成。所以你永远不会得到密码。 您是否已经检查过http://gabiaxel.github.io/spring-social-google-reference/connecting.html 和http://docs.spring.io/spring-social/docs/1.1.x/reference/htmlsingle/#enabling-provider-sign-in-with-code-socialauthenticationfilter-code
【讨论】:
如果您有任何来源,可以与我分享吗?我是一只新蜜蜂,所以理解上面的链接对我来说非常困难以上是关于如何使用 spring security 和 spring boot 对 Google 用户进行身份验证,将 mongoDB 作为存储库?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring Security saml 的 IDP 会话超时
Spring security Saml - SP 和 IDP 的时间差
如何使用 Spring MVC & Security、Jasig CAS 和 JSP 视图在 Spring Boot 2 中配置 UTF-8?
在进行跨域请求时,如何使用 SockJS 和 STOMP 添加 Spring Security JSESSIONID?