如何使用 Spring Security 做一个 RESTful 登录 API?
Posted
技术标签:
【中文标题】如何使用 Spring Security 做一个 RESTful 登录 API?【英文标题】:How to do a RESTful login API using Spring Security? 【发布时间】:2020-12-21 00:03:45 【问题描述】:我刚刚开始使用 Spring 安全性,并且刚刚实现了可以正常工作的 HTTP 基本身份验证。
现在我想创建登录端点并尝试获取经过身份验证的用户。
我不确定我必须为此使用什么?我确实在网上阅读了很多东西,但不知道从哪里开始。
任何提示将不胜感激!
这是用于身份验证的代码。
SecurityConfiguration.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth
.userDetailsService(userDetailsService)
.passwordEncoder(encodePWD());
@Override
protected void configure(HttpSecurity http) throws Exception
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.csrf().disable();
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/rest/**").permitAll()
.and()
.authorizeRequests()
.antMatchers("/secure/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
@Bean
public BCryptPasswordEncoder encodePWD()
return new BCryptPasswordEncoder();
CustomUserDetailsService.java
@Service
public class CustomUserDetailsService implements UserDetailsService
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
User user = userRepository.findByUsername(username);
CustomUserDetails userDetails = null;
if(user != null)
userDetails = new CustomUserDetails();
userDetails.setUser(user);
else
throw new UserNotFoundException("User doesn't exist with this username: " + username);
return userDetails;
CustomUserDetails.java
@Getter
@Setter
public class CustomUserDetails implements UserDetails
private User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities()
return user.getRoles().stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRole())).collect(Collectors.toSet());
@Override
public String getPassword()
return user.getPassword();
@Override
public String getUsername()
return user.getUsername();
@Override
public boolean isAccountNonExpired()
return true;
@Override
public boolean isAccountNonLocked()
return true;
@Override
public boolean isCredentialsNonExpired()
return true;
@Override
public boolean isEnabled()
return true;
更新
我正在使用 Postman 发送我的数据(如 JSON)
"username": "admin",
"password": "admin35"
【问题讨论】:
【参考方案1】:在传统的 MVC Spring Boot 应用程序中,Spring Security 会检查 SecurityContextHolder
以获取身份验证信息。如果没有找到,那么您将被重定向到登录页面。
对于 REST API 端点,您不会收到从服务器发送的典型登录表单。您将从客户端(AngularJS、ReactJS、VueJs、ios 应用程序等)上的表单收集凭据并将凭据发布到端点以检索用户信息。比如下面对用户进行认证,然后将认证后的用户信息返回给客户端。
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@GetMapping("/user")
public ResponseEntity<UserResponse> getUser(@AuthenticationPrincipal DmsUserDetails dmsUser)
logger.info("User " + dmsUser.getFirstName() + " " + dmsUser.getLastName() + " logged in.");
UserResponse user = new UserResponse();
user.setUserId(dmsUser.getUserId());
user.setFirstName(dmsUser.getFirstName());
user.setLastName(dmsUser.getLastName());
user.setEmail(dmsUser.getUsername());
return ResponseEntity.ok(user);
客户端会跟踪用户是否登录,并在每个后续请求中传递 cookie 或令牌。
在本例中,我将端点命名为 /user
,但如果您愿意,也可以将其命名为 /login
。
【讨论】:
嗨,我确实调试了它,我的 loadUserByUsername 方法没有接收到用户名。当我使用 spring 安全表单登录但当我发送数据作为 JSON 用户名为空时,它会收到它。这是我用于身份验证的所有代码。 您如何通过 Postman 发送用户名/密码? Http 基本身份验证需要发送 base64 用户名:密码。如果您使用预定义的基本身份验证授权类型,邮递员将执行此操作。 发送原始 json 请求正文不适用于基本身份验证。您需要单击邮递员中的身份验证选项卡,从下拉框中选择基本身份验证,然后在此处输入您的用户名和密码字段。然后 Postman 将对字段进行 base64 编码并将其发送到身份验证标头中,这正是 Spring Security 所期望的。 是的,当我在邮递员中使用身份验证选项卡时,它可以正常工作。但是,如果我想使用像/login
这样的 rest api 并发送 JSON,那么使用 Basic Auth 是不可能的?因为在这台服务器上,我现在将连接 android 应用程序,并且有一个登录自定义表单......我可以使用一些过滤器,如 UsernamePasswordAuthenticationFilter
还是不可能做到这一点?我是否必须使用 OAuth2 之类的东西或与令牌一起使用的东西?以上是关于如何使用 Spring Security 做一个 RESTful 登录 API?的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security 和 Shiro 该如何选择?
如何使用 Spring Security + Angular 登录/验证
如何使用 DaoAuthenticationProvider 以编程方式使用 Spring Security 对用户进行身份验证
Spring Security 是如何在 Servlet 应用中执行的?