我似乎错过了一些基本的东西:
@SpringBootApplication
public class Application {
User u = new User("USER", "PASSWORD",AuthorityUtils.createAuthorityList(
"ROLE_USER", "ROLE_ADMINISTRATOR"));
@Bean
public UserDetailsService userDetailsService() {
// returning a new User object works fine for every request
return username -> new User("USER", "PASSWORD",
AuthorityUtils.createAuthorityList(
"ROLE_USER", "ROLE_ADMINISTRATOR"));
// returning a previously created User object
// works only for the first request,
// subsequent requests get a 401 error
// return username -> u;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
使用spring-boot-starter-security
依赖项的Spring Boot(v1.5.1)应用程序现在只知道一个用户。此外,只有这个用户才能访问它的所有端点。在我看到的所有工作示例中,UserDetailsService
始终返回类型为User
的新对象,就像上面的示例一样。
但是当它返回先前创建的对象(如上面名为u
的对象)时,只有第一个请求被验证。为什么?
答案 0 :(得分:0)
可以找到一个完整的例子,也可以找到JPA here
这只是一个例子。密码仍然需要加密/保护。
Application.java
package demo;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.repository.CrudRepository;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class Application extends WebMvcConfigurerAdapter {
@Controller
protected static class HomeController {
@RequestMapping("/")
@Secured("ROLE_ADMIN")
public String home(Map<String, Object> model) {
model.put("message", "Hello World");
model.put("title", "Hello Home");
model.put("date", new Date());
return "home";
}
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/access").setViewName("access");
}
@Bean
public ApplicationSecurity applicationSecurity() {
return new ApplicationSecurity();
}
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
protected static class AuthenticationSecurity extends
GlobalAuthenticationConfigurerAdapter {
@Autowired
private Users users;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(users);
}
}
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests().antMatchers("/login").permitAll().anyRequest()
.fullyAuthenticated().and().formLogin().loginPage("/login")
.failureUrl("/login?error").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).and()
.exceptionHandling().accessDeniedPage("/access?error");
// @formatter:on
}
}
}
@Service
class Users implements UserDetailsService {
private UserRepository repo;
@Autowired
public Users(UserRepository repo) {
this.repo = repo;
}
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = repo.findByName(username);
if (user == null) {
return null;
}
List<GrantedAuthority> auth = AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_USER");
if (username.equals("admin")) {
auth = AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
}
String password = user.getPassword();
return new org.springframework.security.core.userdetails.User(username, password,
auth);
}
}
@Repository
interface UserRepository extends CrudRepository<User, Long> {
User findByName(String name);
}
@Entity
class User {
@GeneratedValue
@Id
private Long id;
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
答案 1 :(得分:0)
我认为这是由于Spring User对象在身份验证后清除了密码
请注意,此实现不是一成不变的。它实现了
CredentialsContainer
接口,以便允许在身份验证后删除密码。如果您将实例存储在内存中并重新使用它们,则可能会产生副作用。如果是这样,请确保每次调用UserDetailsService
时都返回一个副本。