【问题标题】:401 error on second controller method call第二个控制器方法调用出现 401 错误
【发布时间】:2019-09-02 15:20:59
【问题描述】:

在我的 Spring 应用程序中,我想向我的 Angular 客户端返回一些信息。首先我向'/login'发送一个请求,这很好。 然后我向'/user'发送HTTP-post请求,它也可以正常工作。但是第二次调用 '/user' 会返回 401 异常。

我在 app.module.ts 中也有一个 XhrInterceptor

这是我的安全配置:

@Configuration
@EnableWebSecurity
public class BasicAuthConfiguration extends WebSecurityConfigurerAdapter {

@Bean("authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) {
    authenticationManagerBuilder
            .authenticationProvider(authenticationProvider());
  }

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userService);
    authProvider.setPasswordEncoder(getPasswordEncoder());

    return authProvider;
  }

@Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/login").permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
    http.cors();
}

Controller.java

@RestController
@Api(tags = "user")
@CrossOrigin(value = "*", allowedHeaders = {"*"})
public class UserController {

  @Resource(name = "authenticationManager")
  private AuthenticationManager authManager;

  @RequestMapping("/login")
  public boolean login(@RequestParam("username") final String username, @RequestParam("password") final String password, final HttpServletRequest request) {
    UsernamePasswordAuthenticationToken authReq =
            new UsernamePasswordAuthenticationToken(username, password);
    Authentication auth = authManager.authenticate(authReq);
    SecurityContext sc = SecurityContextHolder.getContext();
    sc.setAuthentication(auth);
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", sc);
    return
            username.equals("john.doe") && password.equals("passwd");
  }

@RequestMapping(value = "/user")
  public Principal user(HttpServletRequest request) {
    String authToken = request.getHeader("Authorization")
            .substring("Basic".length()).trim();

    return () -> new String(Base64.getDecoder()
            .decode(authToken)).split(":")[0];
  }
}

AuthService.ts

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http: HttpClient, private router: Router) { }

userName: string;

auth() {
    const headers = new HttpHeaders({
      authorization: 'Basic ' + btoa('john.doe:passwd')
    });

    let url = 'http://localhost:8080/login';

    const formData = new FormData();
    formData.append("username", "john.doe")
    formData.append("password", "passwd")

    this.http.post(url, formData, { headers: headers }).subscribe(isValid => {
      if (isValid) {
        console.log("isValid", isValid);

        sessionStorage.setItem('token', btoa('john.doe:passwd'));
        this.router.navigate(['']);
      } else {
        alert("Authentication failed.")
      }
    });
  }


  getUser() {
    let url = 'http://localhost:8080/user';

    let headers: HttpHeaders = new HttpHeaders({
      'Authorization': 'Basic ' + sessionStorage.getItem('token')
    });

    let options = { headers: headers };


    // this.http.post(url, "johndoe").
    this.http.get(url, options).
      subscribe(principal => {
        console.log(principal);

        this.userName = principal['name'];
      },
        error => {
          if (error.status == 401)
            alert('Unauthorized');
        }
      );
  }

LoginComponent.ts

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  constructor(private authService: AuthService, private http: HttpClient,  
  private router: Router) {}

  ngOnInit() {
    sessionStorage.setItem('token', '');
    this.authService.auth()
  }
}

【问题讨论】:

    标签: java angular spring spring-security


    【解决方案1】:

    更新 您可以在您的配置方法中添加它:

       protected void configure(HttpSecurity http) throws Exception {
         http.csrf().disable()
                 .authorizeRequests()
                 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                 .antMatchers("/login").permitAll()
                 .antMatchers("/users").permitAll()
                 .anyRequest()
                 .authenticated()
                 .and()
                 .httpBasic();
         http.cors();
     } 
    

    您希望 Angular 拦截“/user”网址吗?如果是这样,您可以配置一个 ViewController,将您想要的任何 URL 重定向到 index.html,这就是 Angular 读取的内容

    public void addViewControllers(ViewControllerRegistry registry) {
            String forward = "forward:/index.html";
            registry.addViewController("/").setViewName(forward);
            registry.addViewController("/login").setViewName(forward);
            registry.addViewController("/user").setViewName(forward);
        }
    
    

    【讨论】:

    • 我只想从 rest-api 获取一些数据,但是 spring security 不允许我这样做。
    • 您是否在请求中发送了身份验证令牌?
    • 使用您的更新版本,它会起作用,但我不能对每条路径都这样做,因为背后的意义是,如果用户经过身份验证,则只能访问其他路由。 ..是的,我发送
    【解决方案2】:

    我以前不知道,使用“httpBasic()”总是需要对每个请求进行身份验证。因此,我将每个请求中的用户名和密码作为授权标头发送。

    【讨论】:

    • 更好的方法是使用JWT
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 2017-12-10
    • 1970-01-01
    • 2016-06-09
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多