导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
此时启动项目会进入security的登录页面,需要配置一个SecurityConfig类
SecurityConfig
package com.admin.config.security;
import com.admin.filters.CaptchaCodeFilter;
import com.admin.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.admin.service.IUserService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @version 1.0
* @Author 张云飞
* @Date 2021/10/5 0005 18:43
* @注释
*/
@SpringBootConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JxcAuthenticationSuccessHandler jxcAuthenticationSuccessHandler;
@Autowired
private JxcAuthenticationFailedHandler jxcAuthenticationFailedHandler;
@Autowired
private IUserService userService;
@Autowired
private JxcLogoutSuccessHandler logoutSuccessHandler;
@Resource
private CaptchaCodeFilter captchaCodeFilter;
@Resource
private DataSource dataSource;
/*
*
* 放行静态资源
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/css/**",
"/error/**",
"/images/**",
"/js/**",
"/lib/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//禁用csrf跨站攻击
http.csrf().disable()
//图片验证码 用户名密码登录过滤器前执行
.addFilterBefore(captchaCodeFilter,UsernamePasswordAuthenticationFilter.class)
//允许iframe页面嵌套
.headers().frameOptions().disable()
.and()
//配置基于表单登录的一些信息
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/index") //登录的页面
.loginProcessingUrl("/login") //登录的地址 使用框架提供的地址
.successHandler(jxcAuthenticationSuccessHandler) //成功和失败的情况
.failureHandler(jxcAuthenticationFailedHandler)
.and()
.logout()
.logoutUrl("/user/signout")
.deleteCookies("JSESSIONID")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.rememberMe()
.rememberMeParameter("rememberMe")
//保存在浏览器端的cookie的名称,如果不设置默认也是remember-me
.rememberMeCookieName("remember-me-cookie")
//设置token的有效期,即多长时间内可以免密登录,单位是秒
.tokenRepository(persistentTokenRepository())
.and()
//对这两个地址放行,其他不放行
.authorizeRequests().antMatchers("/index","/login","/image").permitAll()
.anyRequest().authenticated();
}
/**
* 配置从数据库中获取token
* @return
*/
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl tokenRepository=new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
}
@Bean
public UserDetailsService userDetailsService(){
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userDetails = (User) userService.findByUsername(username);
System.out.println(username);
//直接返回结果,框架内部会使用结果做登录校验
return userDetails;
}
};
}
//对密码进行加密得到实现方法
@Bean
public PasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
//需要吧UserDetailsService交给框架处理
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(encoder());
}
}
登录成功、失败及退出成功
JxcAuthenticationSuccessHandler
package com.admin.config.security;
import com.admin.model.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @version 1.0
* @Author 张云飞
* @Date 2021/10/5 0005 18:54
* @注释
*/
@Component
public class JxcAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private static ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(
Result.success("登录成功")));
}
}
JxcAuthenticationFailedHandler
package com.admin.config.security;
import com.admin.model.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @version 1.0
* @Author 张云飞
* @Date 2021/10/5 0005 18:57
* @注释
*/
@Component
public class JxcAuthenticationFailedHandler extends SimpleUrlAuthenticationFailureHandler {
private static ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(
Result.error("用户名或密码错误")));
}
}
JxcLogoutSuccessHandler
package com.admin.config.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @version 1.0
* @Author 张云飞
* @Date 2021/10/6 0006 14:50
* @注释
*/
@Component
public class JxcLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/index");
}
}
用户表需要继承UserDetails 并实现它的方法
package com.admin.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serializable;
import java.util.Collection;
/**
* <p>
* 用户表
* </p>
*
* @author 张云飞
* @since 2021-10-01
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_user")
@ApiModel(value="User对象", description="用户表")
public class User implements Serializable, UserDetails {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "备注名")
private String bz;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "真实姓名")
private String trueName;
@ApiModelProperty(value = "用户名")
private String userName;
@ApiModelProperty(value = "备注")
private String remarks;
@ApiModelProperty(value = "是否删除")
private Integer isDel;
@TableField(exist = false)
Collection<? extends GrantedAuthority> authorities;
@TableField(exist = false)
private String roleIds;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
使用springsecurity之后,自定义的拦截器就不需要了
主界面右上角用户信息获取方式改变 使用springSecurity获取登录信息
${(Session.SPRING_SECURITY_CONTEXT.authentication.principal.username)!'zyf'}
controller和service的登录方法都不需要了
修改密码的方式改变,使用Principal获取session中的信息
//借助SpringSecurity获取session中的内容,可以使用Principal
//直接使用形参Principal principal,然后principal.getName()即可获取session中的name属性。
#### 密码加密的两个api
···java
passwordEncoder.encode(password); //传入明文输出密文
passwordEncode.matches("明文","密文"); //将明文与密文进行比对,成功返回true;