最近需要新做一个项目,后端是spring boot ,由于涉及到用户权限验证,于是去看了看spring security,在这里记录一下配置过程
首先引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
我这里应该是比较新的版本,貌似我查了下是5以上的,顺便贴出spring boot版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
这时候启动项目,访问任意路径,你会发现页面转到/login页面
这是security内置的一个页面,如果不做任何配置时,未登录的请求将会被拦截到该页面,这里就不多做解释,接下来增加一些security的配置
创建类SpringSecurityConfig
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)//开启角色验证
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login") // 设置登录页面,未登录的用户将会被拦截到该页面
.failureForwardUrl("/fail") //验证失败时访问
.defaultSuccessUrl("/index").permitAll().and() // 验证成功时访问
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/login",// 设置所有人都可以访问登录页面,也可以不设置,反正被拦截了都是到这
"/amchart/**",
"/bootstrap/**",
"/bootstrap-table/**",
"/css/**",
"/documentation/**",
"/jquery-validation/**",
"/fonts/**",
"/layer/**",
"/js/**",
"/pages/**",
"/plugins/**").permitAll() // 开放常用静态资源权限,这里的根路径为resources下的static
.anyRequest() // 任何请求,登录后可以访问
.authenticated()
.and()
.logout().permitAll();
http.csrf().disable(); // 关闭csrf防护
http.logout().logoutSuccessUrl("/login"); // 注销时访问
}
}
创建类MyUserDetailsService
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class MyUserDetailsService implements UserDetailsService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.info("用户的用户名: {}", username);
// TODO 根据用户名,查找到对应的密码,与权限
String password = passwordEncoder.encode("123456");
logger.info("password: {}", password);
// 参数分别是:用户名,密码,用户权限
User user = new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
/**
* 正常项目这里的user应该是从数据库获取
* User user = userService.findByUserName(username);
*/
if (user != null) {
List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); //权限列表
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");//新建ADMIN角色的权限
grantedAuthorities.add(grantedAuthority);
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);//生成系统用户
} else {
throw new UsernameNotFoundException("admin: " + username + " do not exist!");
}
}
@Bean
public PasswordEncoder passwordEncoder() {
//密码需要加密,这里使用的内建
return new BCryptPasswordEncoder();
}
}
创建类MainController
import com.alibaba.fastjson.JSONObject;
import com.demo.bean.ResponseBean;
import com.demo.bean.User;
import com.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/")
public class MainController {
//登录url,这里一定要用GET,因为我没有重新配置security的登录请求url,默认登录请求是POST的/login
//因为我使用了thymeleaf模板,这里返回login即返回到resources/templates/login.html
//如未使用模板(现在很多需要使用模板),需配置spring.mvc.view.prefix与spring.mvc.view.suffix
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
return "/login";
}
/**
* 考虑到现在很多登录页面页面为异步请求,于是返回了一个json表示请求结果
* 如需挑战则去掉ResponseBody注解,返回页面地址即可
* @param model
* @return
*/
@RequestMapping("/index")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")//匹配ADMIN角色(按照规则,录入权限时,需有一个前缀“ROLE_”,即“ROLE_ADMIN”),非ADMIN角色将被拒绝访问
public String index(Model model) {
JSONObject re = new JSONObject();
re.put("status", true);
return re.toJSONString();
}
@RequestMapping("/fail")
@ResponseBody
public String fail(Model model) {
JSONObject re = new JSONObject();
re.put("status", false);
return re.toJSONString();
}
}
重启项目即可(此处我没有写前端,测试可以随便写一个login页面)
此处的defaultSuccessUrl只对非拦截登录的用户生效
如果你是输入localhost:8080/page/books,然后被拦截到localhost:8080/login,那么当你登录成功时将自动重定向到localhost:8080/page/books
如果需要每次登录成功都到固定页面或返回固定结果,需要将defaultSuccessUrl改为successForwardUrl