이 글은 Ajax 로그인 요청을 처리하는 SpringBoot+SpringSecurity의 문제를 주로 소개하고 있으며, 도움이 필요한 친구들이 참고할 수 있습니다.
최근 프로젝트에서 프론트와 스프링의 분리라는 문제를 겪었습니다. 백엔드, 프런트 엔드는 Vue로 수행되고 모든 데이터 요청은 vue-resource를 사용하여 이루어지며 양식은 사용되지 않으므로 데이터 상호 작용은 모두 JSON을 사용하여 수행되고 Spring Boot는 백그라운드에서 사용되며 Spring Security가 사용됩니다. 권한 확인을 위해 이전에는 Spring Security를 사용하여 페이지를 처리했습니다. 네, 이번에는 단순히 Ajax 요청을 처리하므로 발생한 몇 가지 문제를 기록하겠습니다. 여기의 솔루션은 Ajax 요청에 적합할 뿐만 아니라 모바일 요청 확인 문제도 해결합니다.
프로젝트 만들기
먼저 Spring Boot 프로젝트를 만들어야 합니다. 생성할 때 Web, Spring Security, MySQL 및 MyBatis를 도입해야 합니다(데이터베이스 프레임워크는 실제로 선택 사항입니다. 여기서는 MyBatis를 사용합니다). 생성 후 종속성 파일은 다음과 같습니다.
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.11</version> </dependency>
마지막 commons-codec 종속성은 제가 수동으로 추가했습니다. 이것은 MD5 메시지 다이제스트를 생성하는 데 사용할 수 있는 Apache 오픈 소스 프로젝트입니다. 다음 기사에서는 비밀번호에 대해 간략하게 분석하겠습니다.
데이터베이스 생성 및 구성
로직을 단순화하기 위해 여기에 다음과 같이 사용자 테이블, 역할 테이블, 사용자 역할 연관 테이블이라는 세 개의 테이블을 만들었습니다.
다음으로 애플리케이션을 추가해야 합니다. 여기서는 특정 상황에 따라 .properties에서 데이터베이스를 구성할 수 있습니다.
spring.datasource.url=jdbc:mysql:///vueblog spring.datasource.username=root spring.datasource.password=123
엔티티 클래스 구성
이것은 주로 사용자 클래스 구성을 의미하며 다음과 같이 UserDetails 인터페이스를 구현해야 합니다.
public class User implements UserDetails { private Long id; private String username; private String password; private String nickname; private boolean enabled; private List<Role> roles; @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } @Override public List<GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); for (Role role : roles) { authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName())); } return authorities; } //getter/setter省略... }
구현한 후 UserDetails 인터페이스에는 구현해야 하는 여러 메서드가 있습니다. Boolean을 반환하는 네 가지 메서드는 모두 이름으로 잘 알려져 있습니다. 활성화는 이 필드가 내 데이터베이스에 활성화되어 있는지 여부를 나타냅니다. 쿼리 결과에 따라 반환됩니다. 단순 기간 동안에는 true가 직접 반환됩니다. getAuthorities 메서드는 실제로 역할의 데이터를 List3eefc6b692cb56e4f5b1999c2e0a7477 여기서 주의할 점이 있습니다. 데이터베이스에 저장하는 역할 이름은 모두 '최고 관리자', '일반 사용자' 등이므로 ROLE_
这样的字符开始的,因此需要在这里手动加上 ROLE_
로 시작하지 않습니다.
역할 엔터티 클래스도 있는데, 이는 비교적 간단하고 데이터베이스 필드에 따라 생성될 수 있습니다. 여기서는 자세히 설명하지 않겠습니다.
Create UserService
여기의 UserService도 매우 특별하며 다음과 같이 UserDetailsService 인터페이스를 구현해야 합니다. 인터페이스, 즉 사용자 이름 쿼리 사용자에 따라. MyBatis의 두 개의 Mapper가 여기에 삽입되며, UserMapper는 사용자를 쿼리하는 데 사용되고 RolesMapper는 역할을 쿼리하는 데 사용됩니다. loadUserByUsername 메소드에서는 먼저 들어오는 매개변수(매개변수는 사용자가 로그인할 때 입력한 사용자 이름)를 기반으로 사용자를 쿼리합니다. 발견된 사용자가 null인 경우 UsernameNotFoundException 예외를 직접 발생시킬 수 있지만 처리의 편의를 위해 , 아무 값 없이 A User 객체를 반환하여 후속 비밀번호 비교 프로세스 중에 로그인 실패가 계속 발견되도록 했습니다. (현재 발견된 사용자가 null이 아닌 경우에는 비즈니스 요구에 따라 조정할 수 있습니다.) 그런 다음 사용자 ID로 사용자의 역할을 쿼리하고 쿼리 결과를 사용자 개체에 넣습니다. 이 쿼리 결과는 사용자 개체의 getAuthorities 메서드에 사용됩니다.
보안 구성
먼저 보안 구성을 살펴보고 하나씩 설명하겠습니다.@Service
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Autowired
RolesMapper rolesMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(s);
if (user == null) {
//避免返回null,这里返回一个不含有任何值的User对象,在后期的密码比对过程中一样会验证失败
return new User();
}
//查询用户的角色信息,并返回存入user中
List<Role> roles = rolesMapper.getRolesByUid(user.getId());
user.setRoles(roles);
return user;
}
}
이것이 우리 구성의 핵심입니다. 친구 여러분, 내 말을 들어보세요. one by one :
1 우선 구성 클래스이므로 @Configuration 주석을 추가해야 하며, Spring Security의 구성이므로 WebSecurityConfigurerAdapter를 상속해야 한다는 점을 기억하세요.
2. 방금 생성한 UserService를 삽입합니다. 나중에 사용하겠습니다.
3.configure(AuthenticationManagerBuilder auth)方法中用来配置我们的认证方式,在auth.userDetailsService()方法中传入userService,这样userService中的loadUserByUsername方法在用户登录时将会被自动调用。后面的passwordEncoder是可选项,可写可不写,因为我是将用户的明文密码生成了MD5消息摘要后存入数据库的,因此在登录时也需要对明文密码进行处理,所以就加上了passwordEncoder,加上passwordEncoder后,直接new一个PasswordEncoder匿名内部类即可,这里有两个方法要实现,看名字就知道方法的含义,第一个方法encode显然是对明文进行加密,这里我使用了MD5消息摘要,具体的实现方法是由commons-codec依赖提供的;第二个方法matches是密码的比对,两个参数,第一个参数是明文密码,第二个是密文,这里只需要对明文加密后和密文比较即可(小伙伴如果对此感兴趣可以继续考虑密码加盐)。
4.configure(HttpSecurity http)用来配置我们的认证规则等,authorizeRequests方法表示开启了认证规则配置,antMatchers("/admin/**").hasRole("超级管理员")表示 /admin/**
的路径需要有‘超级管理员'角色的用户才能访问,我在网上看到小伙伴对hasRole方法中要不要加 ROLE_
前缀有疑问,这里是不要加的,如果用hasAuthority方法才需要加。anyRequest().authenticated()表示其他所有路径都是需要认证/登录后才能访问。接下来我们配置了登录页面为login_page,登录处理路径为/login,登录用户名为username,密码为password,并配置了这些路径都可以直接访问,注销登陆也可以直接访问,最后关闭csrf。在successHandler中,使用response返回登录成功的json即可,切记不可以使用defaultSuccessUrl,defaultSuccessUrl是只登录成功后重定向的页面,使用failureHandler也是由于相同的原因。
5.configure(WebSecurity web)方法中我配置了一些过滤规则,不赘述。
6.另外,对于静态文件,如 /images/**
、 /css/**
、 /js/**
这些路径,这里默认都是不拦截的。
Controller
最后来看看我们的Controller,如下:
@RestController public class LoginRegController { /** * 如果自动跳转到这个页面,说明用户未登录,返回相应的提示即可 * <p> * 如果要支持表单登录,可以在这个方法中判断请求的类型,进而决定返回JSON还是HTML页面 * * @return */ @RequestMapping("/login_page") public RespBean loginPage() { return new RespBean("error", "尚未登录,请登录!"); } }
这个Controller整体来说还是比较简单的,RespBean一个响应bean,返回一段简单的json,不赘述,这里需要小伙伴注意的是 login_page
,我们配置的登录页面是一个 login_page
,但实际上 login_page
并不是一个页面,而是返回一段JSON,这是因为当我未登录就去访问其他页面时Spring Security会自动跳转到到 login_page
页面,但是在Ajax请求中,不需要这种跳转,我要的只是是否登录的提示,所以这里返回json即可。
测试
最后小伙伴可以使用POSTMAN或者RESTClient等工具来测试登录和权限问题,我就不演示了。
Ok,经过上文的介绍,想必小伙伴们对Spring Boot+Spring Security处理Ajax登录请求已经有所了解了,好了,本文就说到这里,有问题欢迎留言讨论
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
위 내용은 Ajax 로그인 요청을 처리하는 SpringBoot 및 SpringSecurity 관련 문제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!