pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.power.grid</groupId>
<artifactId>stateGrid</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>stateGrid</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mybatisPlus 核心库 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
创建springboot项目时引入security,jdbc,mysql,web, mybatis, mybatis-plus,mysql dirver;创建好对应的权限控制表的实体类,实现UserDetails接口重写里边的方法
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
//账户是否过期,过期无法验证
@Override
public boolean isAccountNonExpired() {
return true;
}
//指定用户是否被锁定或者解锁,锁定的用户无法进行身份验证
@Override
public boolean isAccountNonLocked() {
return true;
}
//指示是否已过期的用户的凭据(密码),过期的凭据防止认证
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//是否被禁用,禁用的用户不能身份验证
@Override
public boolean isEnabled() {
return true;
}
//如果用户表有对应的字段再重写这些方法
创建UserService接口继承UserDetailsService
public interface WdpUserService extends UserDetailsService {
}
创建UserServiceImpl实现类实现UserService接口,重写UserDetails方法
@Service
public class WdpUserServiceImpl implements WdpUserService {
@Autowired
private WdpUserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserTable user = userMapper.findUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名或密码错误");
}else {
user.setLogintime((int) (System.currentTimeMillis() / 1000));
userMapper.saveLoginTime(user.getLogintime(),user.getId());
return user;
}
}
}
然后写dao层、xml查询用户的sql逻辑就完成了,最后加上SecurityConfig配置类
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/images/**","/upload/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
/*.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("admin", "user")*/
.antMatchers("/doLogin").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
.successHandler((req, resp, authentication) -> {
Object principal = authentication.getPrincipal();
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, authentication);
String resStr = new ObjectMapper().writeValueAsString(principal);
WdpUserTable user = JSON.parseObject(resStr,WdpUserTable.class);
Map<String,Object> map = new HashMap<>();
map.put("id",user.getId());
map.put("loginname",user.getLoginname());
map.put("username",user.getUsername());
map.put("function",user.getFunction());
map.put("JSESSIONID",request.getSession().getId());
Result result = Result.ofSuccess(map);
out.write(JSON.toJSONString(result));
out.flush();
out.close();
})
.failureHandler((req, resp, e) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Result result = Result.ofFail(404,"用户名或密码错误");
out.write(JSON.toJSONString(result));
out.flush();
out.close();
})
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler((req, resp, authentication) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("注销成功");
out.flush();
out.close();
})
.permitAll()
.and()
.csrf().disable().exceptionHandling()
.authenticationEntryPoint((req, resp, authException) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("尚未登录,请先登录");
out.flush();
out.close();
}
);
}
}
注意:SpringSecurity实现继承了UserDetails,不能直接修改成前端想要的返回格式,它是没有controller的,访问控制都在配置类里,所以修改成前端想要的格式要在这里修改,out.write()才是框架返回给前端的内容;
String resStr = new ObjectMapper().writeValueAsString(principal);
WdpUserTable user = JSON.parseObject(resStr,WdpUserTable.class);
Map<String,Object> map = new HashMap<>();
map.put("id",user.getId());
map.put("loginname",user.getLoginname());
map.put("username",user.getUsername());
map.put("function",user.getFunction());
map.put("JSESSIONID",request.getSession().getId());
Result result = Result.ofSuccess(map);
out.write(JSON.toJSONString(result));
SpringSecurity 的关键配置解析:
authentication 用户的认证对象
denyAll 结果始终为false
hasAnyRole(list of roles) 如果用户被授予了列表中任意的指定角色,结果为true
hasRole(role) 如果用户被授予了指定的角色,结果为true
hasIpAddress(IPAddress) 如果请求来自指定IP的话,结果为true
isAnonymous() 如果当前用户为匿名用户,结果为true
isAuthenticated() 如果当前用户进行了认证的话,结果为true
isFullyAuthenticated() 如果当前用户进行了完整认证的话(不是通过Remember-me功能进行的认证),结果为true
isRememberMe() 如果当前用户是通过Remember-me自动认证的,结果为true
permitAll() 结果始终为true
principal() 用户的principal对象