Spring 安全 REST 登录
Spring Security REST Login
我遇到了关于使用具有 Spring 安全性的 REST API 登录的问题。至于使用 Spring 提供的默认登录名 window 登录,安全性正在运行并且正在使用数据库进行身份验证,我不知道如何进行自己的登录。我知道如何用我自己的表格替换表格,但我应该将数据发送到哪里?我应该 POST 它用于某个地址吗?我用用户名和密码制作了基本表格。
您可以将用户名和密码存储在数据库中,您可以使用它来登录用户。您创建自己的 class 扩展 WebSecurityConfigurerAdapter 并覆盖您需要修改的方法:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.jdbcAuthentication()
.dataSource(dataSource)
}
}
但要注意 Spring 搜索用户名和密码时的安全默认数据库查询,这样您就可以创建良好的数据库模式:
public static final String DEF_USERS_BY_USERNAME_QUERY =
"select username,password,enabled " +
"from users " +
"where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
"select username,authority " +
"from authorities " +
"where username = ?";
public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =
"select g.id, g.group_name, ga.authority " +
"from groups g, group_members gm, group_authorities ga " +
"where gm.username = ? " +
"and g.id = ga.group_id " +
"and g.id = gm.group_id";
但您也可以使用Spring方法来指定您自己对数据库的查询:
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username, password, enabled from Users " +
"where username=?")
您应该POST将您的数据传输到您创建的某个服务,该服务将存储用户并传递给数据库。
试试这个,它可能会帮助您...至少了解您缺少什么。
此代码不能保证 100% 有效,某些部分是故意遗漏的(错误处理及其格式、加载用户、一些检查、Session API)。
基本思想是您必须注册一个过滤器(对身份验证过程的所有安全请求做出反应)和一个稍后能够加载经过身份验证的用户并为您创建安全上下文的提供程序(例如,您知道每个请求按线程处理,可以通过 SecurityContextHolder/ThreadLocal).
获得此用户
并且您需要创建一个单独的控制器来处理创建用户 session 又名 login/Authorization 的初始情况。此 API 的响应必须包含一些 session 的 GUID,以便稍后将其用作 header 的值:Authentication: Bearer <value>
一些规格:https://www.rfc-editor.org/rfc/rfc6750
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//optional
@Import(RestSecurityConfig.TokenAuthenticationProvider.class)// one of the way to create spring bean
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/actuator/*"),
new AntPathRequestMatcher("/some_api_to_login", POST), // this must be public
);
private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);
// better to move it out as a separate class
public static class TokenAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Override
public boolean supports(Class<?> authentication) {
return MyAuthenticationToken.class.isAssignableFrom(authentication);
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
return null; // service/dao.loadUser
}
}
public static class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public TokenAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
Authentication auth = new MyAuthenticationToken(request.getHeader("Authentication"));
return getAuthenticationManager().authenticate(auth);
}
}
@Autowired
TokenAuthenticationProvider authenticationProvider;
@Override
protected void configure(final AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider);
}
@Override
public void configure(final WebSecurity web) {
web.ignoring().requestMatchers(PUBLIC_URLS);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// maybe some of the tuning you might not need
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), PROTECTED_URLS).and()
.authorizeRequests().anyRequest().authenticated().and()
.cors().and()
.anonymous().disable()
.rememberMe().disable()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
// it's important
http.addFilterBefore(tokenAuthenticationFilter(), AnonymousAuthenticationFilter.class);
}
@Bean
AbstractAuthenticationProcessingFilter tokenAuthenticationFilter() throws Exception {
final AbstractAuthenticationProcessingFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
// maybe error handling to provide some custom response?
return filter;
}
// it's critically important to register your filter properly in spring context
/** Disable Spring boot automatic filter registration. */
@Bean
FilterRegistrationBean disableRegistrationForAuthenticationFilter(final TokenAuthenticationFilter filter) {
final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
// this one also is critically important to avoid redirection
@Bean
SimpleUrlAuthenticationSuccessHandler successHandler() {
final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
successHandler.setRedirectStrategy(new NoRedirectStrategy());
return successHandler;
}
}
我遇到了关于使用具有 Spring 安全性的 REST API 登录的问题。至于使用 Spring 提供的默认登录名 window 登录,安全性正在运行并且正在使用数据库进行身份验证,我不知道如何进行自己的登录。我知道如何用我自己的表格替换表格,但我应该将数据发送到哪里?我应该 POST 它用于某个地址吗?我用用户名和密码制作了基本表格。
您可以将用户名和密码存储在数据库中,您可以使用它来登录用户。您创建自己的 class 扩展 WebSecurityConfigurerAdapter 并覆盖您需要修改的方法:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.jdbcAuthentication()
.dataSource(dataSource)
}
}
但要注意 Spring 搜索用户名和密码时的安全默认数据库查询,这样您就可以创建良好的数据库模式:
public static final String DEF_USERS_BY_USERNAME_QUERY =
"select username,password,enabled " +
"from users " +
"where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
"select username,authority " +
"from authorities " +
"where username = ?";
public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =
"select g.id, g.group_name, ga.authority " +
"from groups g, group_members gm, group_authorities ga " +
"where gm.username = ? " +
"and g.id = ga.group_id " +
"and g.id = gm.group_id";
但您也可以使用Spring方法来指定您自己对数据库的查询:
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username, password, enabled from Users " +
"where username=?")
您应该POST将您的数据传输到您创建的某个服务,该服务将存储用户并传递给数据库。
试试这个,它可能会帮助您...至少了解您缺少什么。 此代码不能保证 100% 有效,某些部分是故意遗漏的(错误处理及其格式、加载用户、一些检查、Session API)。
基本思想是您必须注册一个过滤器(对身份验证过程的所有安全请求做出反应)和一个稍后能够加载经过身份验证的用户并为您创建安全上下文的提供程序(例如,您知道每个请求按线程处理,可以通过 SecurityContextHolder/ThreadLocal).
获得此用户并且您需要创建一个单独的控制器来处理创建用户 session 又名 login/Authorization 的初始情况。此 API 的响应必须包含一些 session 的 GUID,以便稍后将其用作 header 的值:Authentication: Bearer <value>
一些规格:https://www.rfc-editor.org/rfc/rfc6750
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//optional
@Import(RestSecurityConfig.TokenAuthenticationProvider.class)// one of the way to create spring bean
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/actuator/*"),
new AntPathRequestMatcher("/some_api_to_login", POST), // this must be public
);
private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);
// better to move it out as a separate class
public static class TokenAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Override
public boolean supports(Class<?> authentication) {
return MyAuthenticationToken.class.isAssignableFrom(authentication);
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
return null; // service/dao.loadUser
}
}
public static class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public TokenAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
Authentication auth = new MyAuthenticationToken(request.getHeader("Authentication"));
return getAuthenticationManager().authenticate(auth);
}
}
@Autowired
TokenAuthenticationProvider authenticationProvider;
@Override
protected void configure(final AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider);
}
@Override
public void configure(final WebSecurity web) {
web.ignoring().requestMatchers(PUBLIC_URLS);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// maybe some of the tuning you might not need
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), PROTECTED_URLS).and()
.authorizeRequests().anyRequest().authenticated().and()
.cors().and()
.anonymous().disable()
.rememberMe().disable()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
// it's important
http.addFilterBefore(tokenAuthenticationFilter(), AnonymousAuthenticationFilter.class);
}
@Bean
AbstractAuthenticationProcessingFilter tokenAuthenticationFilter() throws Exception {
final AbstractAuthenticationProcessingFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
// maybe error handling to provide some custom response?
return filter;
}
// it's critically important to register your filter properly in spring context
/** Disable Spring boot automatic filter registration. */
@Bean
FilterRegistrationBean disableRegistrationForAuthenticationFilter(final TokenAuthenticationFilter filter) {
final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
// this one also is critically important to avoid redirection
@Bean
SimpleUrlAuthenticationSuccessHandler successHandler() {
final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
successHandler.setRedirectStrategy(new NoRedirectStrategy());
return successHandler;
}
}