这里我对springboot不做过多描述,因为我觉得学这个的肯定掌握了springboot这些基础
org.springframework.boot
spring‐boot‐starter‐security
@Configuration
public class WebConfig implements WebMvcConfigurer {
//默认Url根路径跳转到/login,此url为spring security提供
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("redirect:/login");
}
}
Spring Security为我们提供了登录页面,这里我是将 "/",路径设置为登陆页面的路径,方便测试,
也可以自定义登录页面,我会在后面说明
server.port=8080
server.servlet.context-path=/security-springboot
spring.application.name = security-springboot
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
spring.datasource.url=jdbc:mysql://localhost:3306/user_db
spring.datasource.username=root
spring.datasource.password=XXXX
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
至于为什么不是yml,这完全不是这里的重点,关于前端用的jsp,各位看官姥爷们也凑合看吧,理解这个框架就好,最下面的数据库配置这里也可以先不做,后面也会详细说明
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//定义用户信息服务(查询用户信息)
/*
@Bean
public UserDetailsService userDetailsService(){
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
return manager;
}
*/
//密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//安全拦截机制(最重要)
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
// .antMatchers("/r/r1").hasAuthority("p2")
// .antMatchers("/r/r2").hasAuthority("p2")
.antMatchers("/r/**").authenticated()//所有/r/**的请求必须认证通过
.anyRequest().permitAll()//除了/r/**,其它的请求可以访问
.and()
.formLogin()//允许表单登录
.loginPage("/login-view")//登录页面
.loginProcessingUrl("/login")
.successForwardUrl("/login-success")//自定义登录成功的页面地址
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login-view?logout");
}
}
如果不想连接数据库测试,这里可以先把这些注释解除掉去掉,用模拟数据
@RestController
public class LoginController {
@RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})
public String loginSuccess(){
//提示具体用户名称登录成功
return getUsername()+" 登录成功";
}
/**
* 测试资源1
* @return
*/
@GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})
public String r1(){
return "访问资源1";
}
/**
* 测试资源2
* @return
*/
@GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})
public String r2(){
return " 访问资源2";
}
}
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class> var1);
}
public boolean supports(Class> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
public interface Authentication extends Principal, Serializable {
Collection extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean var1) throws IllegalArgumentException;
}
public interface UserDetails extends Serializable {
Collection extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
public interface PasswordEncoder {
String encode(CharSequence var1);
boolean matches(CharSequence var1, String var2);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
(不过后面我们都会从数据库中拿)
@Configuration//就相当于springmvc.xml文件
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("redirect:/login-view");
registry.addViewController("/login-view").setViewName("login");
}
}
//配置安全拦截机制
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/r/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin() (1)
.loginPage("/login‐view") (2)
.loginProcessingUrl("/login") (3)
.successForwardUrl("/login‐success") (4)
.permitAll();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //屏蔽CSRF控制,即spring security不再限制CSRF
...
}
CREATE DATABASE `user_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL COMMENT '用户id',
`username` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`fullname` varchar(255) NOT NULL COMMENT '用户姓名',
`mobile` varchar(11) DEFAULT NULL COMMENT '手机号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC
spring.datasource.url=jdbc:mysql://localhost:3306/user_db
spring.datasource.username=root
spring.datasource.password=mysql
spring.datasource.driver‐class‐name=com.mysql.jdbc.Driver
org.springframework.boot
spring‐boot‐starter‐jdbc
mysql
mysql‐connector‐java
5.1.47
pom.xml添加依赖,mysql版本根据自己情况
@Data
public class UserDto {
private String id;
private String username;
private String password;
private String fullname;
private String mobile;
}
@Repository
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
public UserDto getUserByUsername(String username){
String sql ="select id,username,password,fullname from t_user where username = ?";
List list = jdbcTemplate.query(sql, new Object[]{username}, new
BeanPropertyRowMapper<>(UserDto.class));
if(list == null && list.size() <= 0){
return null;
}
return list.get(0);
}
}
@Service
public class SpringDataUserDetailsService implements UserDetailsService {
@Autowired
UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//登录账号
System.out.println("username="+username);
//根据账号去数据库查询...
UserDto user = userDao.getUserByUsername(username);
if(user == null){
return null;
}
//这里暂时使用静态数据
UserDetails userDetails =
User.withUsername(user.getFullname()).password(user.getPassword()).authorities("p1").build();
return userDetails;
}
}
WebSecurityConfig中
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@RestController
public class LoginController {
@RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})
public String loginSuccess(){
//提示具体用户名称登录成功
return getUsername()+" 登录成功";
}
/**
* 测试资源1
* @return
*/
@GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})
public String r1(){
return getUsername()+" 访问资源1";
}
/**
* 测试资源2
* @return
*/
@GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})
public String r2(){
return getUsername()+" 访问资源2";
}
//获取当前用户信息
private String getUsername(){
String username = null;
//当前认证通过的用户身份
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//用户身份
Object principal = authentication.getPrincipal();
if(principal == null){
username = "匿名";
}
if(principal instanceof org.springframework.security.core.userdetails.UserDetails){
UserDetails userDetails = (UserDetails) principal;
username = userDetails.getUsername();
}else{
username = principal.toString();
}
return username;
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
}
server.servlet.session.timeout = 3600s
http.sessionManagement()
.expiredUrl("/login‐view?error=EXPIRED_SESSION")
.invalidSessionUrl("/login‐view?error=INVALID_SESSION");
server.servlet.session.cookie.http‐only = trueserver.servlet.session.cookie.secure = true
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login‐view?logout");
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
//...
.and()
.logout() (1)
.logoutUrl("/logout") (2)
.logoutSuccessUrl("/login‐view?logout") (3)
.logoutSuccessHandler(logoutSuccessHandler) (4)
.addLogoutHandler(logoutHandler) (5)
.invalidateHttpSession(true); (6)
}