【问题标题】:How to get a username from post method in spring security?如何从 Spring Security 中的 post 方法获取用户名?
【发布时间】:2019-07-24 21:36:21
【问题描述】:

我在应用程序中使用spring-bootspring-security。我的目标是从post 方法中获取当前注册用户的用户名。 Get 方法运行良好,但 post 方法不起作用。为什么?我该如何解决这个问题?

测试控制器

@GetMapping("/test")
public String test(Authentication authentication) {
    System.out.println(authentication.getName()); // <--------- It's working
    return "testfile";
}

@PostMapping("/test")
public String testPost(Authentication authentication) {
    System.out.println(authentication.getName()); // <--------- NOLL ERROR!
    return "testfile";
}

错误

java.lang.NullPointerException: null

用户

@Entity
@Table(name="user")
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private long id;
    @Column(name="mail")
    private String mail;
    @Column(name="password")
    private String password;
}

用户DAO

@Repository
public class UserDAO {
    @Autowired
    private EntityManager entityManager;
    public List<User> findAll() {
        return entityManager.unwrap(Session.class).createQuery("from User", User.class).getResultList();
    }
    public User findByMail(String mail){
        Session currentSession = entityManager.unwrap(Session.class);
        Query theQuery = currentSession.createQuery("from User where mail=:mail", User.class);
        theQuery.setParameter("mail", mail);
        List<User> users = theQuery.getResultList();
        if(users.isEmpty()){
            return new User();
        }
        return users.get(0);
    }
    public void saveOrUpdate(User user) {
        Session currentSession = entityManager.unwrap(Session.class);
        currentSession.saveOrUpdate(user);
    }
}

用户服务

public interface UserService extends UserDetailsService{
    public List<User> findAll();
    public User findByMail(String mail);
    public void saveOrUpdate(User user);
}

UserServiceImpl

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDAO userDAO;
    @Autowired
    private UserRoleDAO userRoleDAO;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    @Override
    @Transactional
    public List<User> findAll() {
        return userDAO.findAll();
    }
    @Override
    @Transactional
    public User findByMail(String mail){
       return userDAO.findByMail(mail);
    }
    @Override
    @Transactional
    public void saveOrUpdate(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        userDAO.saveOrUpdate(user);
    }
    @Override
    @Transactional
    public UserDetails loadUserByUsername(String mail) throws UsernameNotFoundException {
        User user = userDAO.findByMail(mail);
        List<UserRole> userRole = userRoleDAO.findByUserId(user.getId());
        if (user == null) {
            throw new UsernameNotFoundException("Invalid username or password.");
        }
        return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), mapRolesToAuthorities(userRole));
    }
    private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<UserRole> roles) {
        return roles.stream().map(role -> new SimpleGrantedAuthority(role.getRole())).collect(Collectors.toList());
    }
}

安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private Environment env;

@Autowired
private DataSource dataSource;

@Autowired
private UserService userService;

RedirectAuthenticationSuccessHandler redirectAuthenticationSuccessHandler = new RedirectAuthenticationSuccessHandler();

RedirectAuthenticationFailureHandler redirectAuthenticationFailureHandler = new RedirectAuthenticationFailureHandler();

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication().dataSource(dataSource)
            .usersByUsernameQuery(env.getProperty("my.usersbyusernamequery"))
            .authoritiesByUsernameQuery(env.getProperty("my.authoritiesbyusernamequery"));
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.authorizeRequests()
            .antMatchers("/anypage1/**").hasRole("MANAGER")
            .antMatchers("/anypage2/**").hasRole("ADMIN")
            .antMatchers("/test").hasRole("ADMIN")
            .authenticated()
            .antMatchers("/**").permitAll()
            .and()
            .formLogin().loginPage("/login").failureHandler(redirectAuthenticationFailureHandler)
            .loginProcessingUrl("/login-control").successHandler(redirectAuthenticationSuccessHandler).permitAll()
            .and()
            .logout().logoutUrl("/logout").permitAll().and().exceptionHandling().accessDeniedPage("/access-denied");
}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.POST, "/anypage3").antMatchers(HttpMethod.POST, "/anypage4")
                  .antMatchers(HttpMethod.POST, "/test");
}

@Bean
public BCryptPasswordEncoder passwordEncoder()
{
    return new BCryptPasswordEncoder();
}

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
    auth.setUserDetailsService(userService);
    auth.setPasswordEncoder(passwordEncoder());
    return auth;
}

}

【问题讨论】:

  • 你能分享整个安全配置吗?
  • 好的,你现在可以检查安全配置了。

标签: spring-boot spring-security


【解决方案1】:
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.POST, "/anypage3").antMatchers(HttpMethod.POST, "/anypage4")
                  .antMatchers(HttpMethod.POST, "/test");
}

你在post方法中忽略了/test,所以它不会被spring安全过滤器过滤,尝试删除它。

【讨论】:

  • 我按照你说的修改了代码,现在可以使用了。谢谢!
【解决方案2】:

您可以从 SecurityContextHolder 获取用户名

用户用户 = (用户)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 字符串名称 = user.getUsername(); //获取当前登录用户名

在 loadUserByUsername 方法中,您可以在 SecurityContextHolder 上手动设置身份验证令牌,您可以在控制器中使用相同的令牌

UsernamePasswordWithAttributesAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loadUserByUsername(username), password, authorities );
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

【讨论】:

  • 请参考此链接。希望对解决您的问题有所帮助stackoverflow.com/a/36936819/1838148
  • 我的问题还在继续。作为一种解决方法,我将username 传递给HttpSession
  • 您需要在 SecurityContextHolder 中设置用户名,同时验证您的用户名和密码。如果用户名有效,则将其设置为 SecurityContextHolder 并在每个控制器调用中使用。
  • 你能检查我的代码,我在哪里犯错了吗? :)
猜你喜欢
  • 1970-01-01
  • 2015-12-06
  • 2012-01-30
  • 2021-08-26
  • 2014-06-18
  • 2017-04-04
  • 2015-09-19
  • 2014-05-05
  • 2012-11-10
相关资源
最近更新 更多