JAVA——springSecurity——自定义配置的一些补充:Anonymous匿名用户重写loadUserByUsername()方法自定义WebSecurityConfig配置等
Posted 叶不修233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA——springSecurity——自定义配置的一些补充:Anonymous匿名用户重写loadUserByUsername()方法自定义WebSecurityConfig配置等相关的知识,希望对你有一定的参考价值。
JAVA——springSecurity——自定义配置的一些补充:Anonymous匿名用户、重写loadUserByUsername()方法、自定义WebSecurityConfig配置等
- 三、一些细节补充
三、一些细节补充
(1)Anonymous匿名用户
未登录的情况下发起一个非认证请求,系统会自动生成一个匿名对象anonymoususer,但这个匿名用户不包含任何权限
AnonymousAuthenticationFilter类——doFilter()方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
//获取当前 spring security的上下文对象,从上下文对象中获取一个对象authentication(Token - 标志,象征)。
if (SecurityContextHolder.getContext().getAuthentication() == null)
//如果为空,说明用户未登录(用户如果登录会往上下文中存入这个东西),那就调用createAuthentication()方法创建一个匿名用户,并把这个匿名用户存入上下文
SecurityContextHolder.getContext().setAuthentication(this.createAuthentication((HttpServletRequest)req));
if (this.logger.isDebugEnabled())
this.logger.debug("Populated SecurityContextHolder with anonymous token: '" + SecurityContextHolder.getContext().getAuthentication() + "'");
else if (this.logger.isDebugEnabled())
this.logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '" + SecurityContextHolder.getContext().getAuthentication() + "'");
chain.doFilter(req, res);
AnonymousAuthenticationFilter类——createAuthentication()方法
protected Authentication createAuthentication(HttpServletRequest request)
//创建一个匿名对象auth
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(this.key, this.principal, this.authorities);
auth.setDetails(this.authenticationDetailsSource.buildDetails(request));
return auth;
(2)重写loadUserByUsername()方法
要想从自定义的数据库中读取账号和密码,可以在我们自定义的配置类WebSecurityConfig中配置,只需要两步:
1.重新定制DaoAuthenticationProvider
2.指定认证管理器为自定义的管理器
3.在用户业务实现类UserServiceImpl中重写loadUserByUsername(username)方法,使用户名通过访问数据库得到
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserServiceImpl userServiceImpl;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
//在内存中配置用户名和密码
// auth.inMemoryAuthentication().withUser("tom")
// .password(passwordEncoder.encode("123")).roles();
// auth.inMemoryAuthentication().withUser("admin")
// .password(passwordEncoder.encode("admin")).roles();
//2.指定认证管理器
auth.authenticationProvider(getDaoAuthenticationProvider());
/**
* 1.重新定制DaoAuthenticationProvider
* @return
*/
@Bean
public DaoAuthenticationProvider getDaoAuthenticationProvider()
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
//设置用户未找到的异常不隐藏
provider.setHideUserNotFoundExceptions(false);
//设置认证管理器使用userServiceImpl对象
provider.setUserDetailsService(userServiceImpl);
//设置认证管理器使用的密码管理对象
provider.setPasswordEncoder(passwordEncoder);
return provider;
/**
* <p>
* 服务实现类
* </p>
* 实现了UserDetailsService接口,重写它的loadUserByUsername方法
* 使springSecurity从内存中读取账号密码改成从我们自定义的数据库中读取帐号密码
* @author z
* @since 2022-07-05
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService, UserDetailsService
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 重写了UserDetailsService接口的loadUserByUsername方法
* 从数据库读取用户名和密码
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException
//3.访问数据库,根据用户名查询用户对象
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
User user = userMapper.selectOne(wrapper);
if(user==null)
throw new UsernameNotFoundException("用户名不存在!");
//查询用户的权限集
List<String> permList = userMapper.getPerCodesByPerm(user.getUsername());
//封装用户的权限集
List<GrantedAuthority> authorities = new ArrayList<>();
permList.forEach(perm->
authorities.add(new SimpleGrantedAuthority(perm));
);
Boolean isEnabled = true;
Boolean isAccountNonExpired = true;
Boolean isCredentialsNonExpired = true;
Boolean isAccountNonLocked = true;
if(user.getStatus().equals("1"))
//用户不可用
isEnabled = false;
else if(user.getStatus().equals("2"))
//账户已过期
isAccountNonExpired=false;
else if(user.getStatus().equals("3"))
//凭据已过期
isCredentialsNonExpired=false;
else if(user.getStatus().equals("4"))
//账户已锁定
isAccountNonLocked=false;
UserDetails userDetails =
new org.springframework.security.core.userdetails.User(
user.getUsername(),
passwordEncoder.encode(user.getPassword()),
isEnabled,
isAccountNonExpired,
isCredentialsNonExpired,
isAccountNonLocked,
authorities);
return userDetails;
(3)自定义响应结果ResponseResult工具类
@Data
public class ResponseResult<T>
private int status;
private String msg;
private T data;
public ResponseResult()
public ResponseResult(int status, String msg)
this.status = status;
this.msg = msg;
public ResponseResult(T data, String msg, int status)
this(status,msg);
this.data = data;
this.msg = msg;
public static ResponseResult ok()
ResponseResult result = new ResponseResult();
result.setStatus(ResultCode.SUCCESS.getCode());
result.setMsg(ResultCode.SUCCESS.getMessage());
return result;
public static ResponseResult error(ResultCode resultCode)
ResponseResult result = new ResponseResult();
result.setStatus(resultCode.getCode());
result.setMsg(resultCode.getMessage());
return result;
public static ResponseResult<Void> SUCCESS = new ResponseResult<>(200,"成功");
public static ResponseResult<Void> INTEVER_ERROR = new ResponseResult<>(500,"服务器错误");
public static ResponseResult<Void> NOT_FOUND = new ResponseResult<>(404,"未找到");
(4)自定义状态码和对应msg工具类ResultCode
public enum ResultCode
/* 成功 */
SUCCESS(200, "成功"),
/* 默认失败 */
COMMON_FAIL(999, "失败"),
/* 参数错误:1000~1999 */
PARAM_NOT_VALID(1001, "参数无效"),
PARAM_IS_BLANK(1002, "参数为空"),
PARAM_TYPE_ERROR(1003, "参数类型错误"),
PARAM_NOT_COMPLETE(1004, "参数缺失"),
/* 用户错误 */
USER_NOT_LOGIN(2001, "用户未登录"),
USER_ACCOUNT_EXPIRED(2002, "账号已过期"),
USER_CREDENTIALS_ERROR(2003, "密码错误"),
USER_CREDENTIALS_EXPIRED(2004, "密码过期"),
USER_ACCOUNT_DISABLE(2005, "账号不可用"),
USER_ACCOUNT_LOCKED(2006, "账号被锁定"),
USER_ACCOUNT_NOT_EXIST(2007, "账号不存在"),
USER_ACCOUNT_ALREADY_EXIST(2008, "账号已存在"),
USER_ACCOUNT_USE_BY_OTHERS(2009, "您的登录已经超时或者已经在另一台机器登录,您被迫下线"),
TOKEN_IS_NULL(2010,"TOKEN为空"),
TOKEN_INVALID_EXCEPTION(2011,"TOKEN非法"),
/* 业务错误 */
NO_PERMISSION(4001, "没有权限"),
/*部门错误*/
DEPARTMENT_NOT_EXIST(5007, "部门不存在"),
DEPARTMENT_ALREADY_EXIST(5008, "部门已存在"),
/*运行时异常*/
ARITHMETIC_EXCEPTION(9001,"算数异常"),
NULL_POINTER_EXCEPTION(9002,"空指针异常"),
ARRAY_INDEX_OUTOfBOUNDS_EXCEPTION(9003,"数组越界");
ResultCode(Integer code, String message)
this.code = code;
this.message = message;
private Integer code;
public Integer getCode()
return code;
private String message;
public String getMessage()
return message;
(5)自定义WebSecurityConfig配置
主要有三项:
1.SpringSecurity 自带HttpBasic基础认证模式
2.默认formLogin表单模式
3.自定义formLogin表单模式
5-1 HttpBasic模式登录认证
SpringSecurity 自带一种基础认证模式
实现方式:创建WebSecurityConfig配置类
/**
* Spring Securtiy配置类
*/
@Configuration //配置类
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
super.configure(auth);
@Override
public void configure(WebSecurity web) throws Exception
super.configure(web);
@Override
protected void configure(HttpSecurity http) throws Exception
//开启httpBasci模式登录认证
http.httpBasic()
//每个模块配置使用and结尾
.and()
//配置路径拦截,表明路径访问所对应的权限,角色,认证信息
.authorizeRequests()
.anyRequest()
//所有请求都需要登录认证才能访问
.authenticated();
5-2 默认formLogin表单模式
注释掉上面的配置类,通过applicaton.yml配置用户名与密码
spring:
security:
user:
name: tom
password: tom
5-3 自定义formLogin表单模式
继承WebSecurityConfigurerAdapter类,实现它的三个configure方法
//@Configuration
@EnableWebSecurity //涵盖了 @Configuration 注解
//@EnableGlobalMethodSecurity(jsr250Enabled = true)
//@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启Security注解鉴权的功能
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserServiceImpl userServiceImpl;
@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Autowired
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Autowired
private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
@Autowired
private MyAccessDeniedHandler myAccessDeniedHandler;
@Autowired
private JwtTokenAuthenticationFilter jwtTokenAuthenticationFilter;
@Autowired
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
//在内存中配置用户名和密码
// auth.inMemoryAuthentication().withUser("tom")
// .password(passwordEncoder.encode("123")).roles();
// auth.inMemoryAuthentication().withUser("admin")
// .password(passwordEncoder.encode("admin")).roles();
//从指定的数据库读取账号密码
// auth.userDetailsService(userServiceImpl).passwordEncoder(passwordEncoder);
//指定认证管理器
auth.authenticationProvider(getDaoAuthenticationProvider());
@Override
public void configure(WebSecurity web) throws Exception
super.configure(web);
@Override
protected void configure(HttpSecurity http) throws Exception
//开启httpBasic认证
// http.httpBasic()
// //每个模块配置使用and结尾
// .and()
// //配置路径拦截,表明路径访问所对应的权限,角色,认证信息
// .authorizeRequests()
// .anyRequest()
// //所有请求都需要登录认证才能访问
// .authenticated();
//http.httpBasic().and().authorizeRequests().anyRequest().authenticated(); //关闭httpBasic认证
//开启自定义formLogin表单认证
//需要放行的url在这里配置,必须要放行/login和/login.html,不然会报错
http.authorizeRequests().antMatchers("/login", "/login.html")
.permitAll().anyRequest().authenticated().and().
// 设置登陆页、登录表单form中action的地址,也就是处理认证请求的路径
formLogin().loginPage("/login.html").loginProcessingUrl("/login")
//登录表单form中密码输入框input的name名,不修改的话默认是password
.usernameParameter("username").passwordParameter("password")
//登录认证成功后默认转跳的路径
// .defaultSuccessUrl("/home")
//登陆成功后不跳转,返回json数据
.successHandler(myAuthenticationSuccessHandler)
//登录认证失败后,被放行的请求
//注意,此请求不能为error,因为已经被springSecurity定义
// .failureUrl("/gotoError1").permitAll();
//登录认证失败后,不跳转,返回json数据
.failureHandler(myAuthenticationFailureHandler)
.and()
.exceptionHandling()
.authenticationEntryPoint(myAuthenticationEntryPoint)
.accessDeniedHandler(myAccessDeniedHandler)
.and().logout().logoutSuccessHandler(myLogoutSuccessHandler);
//将自定义的JwtTokenAuthenticationFilter插入到过滤器链的指定过滤器前面
http.addFilterBefore(jwtTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
//关闭CSRF跨域
http.csrf().disable();
//关闭session最严格的策略
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
如何使用 Java 配置表示 Spring Security“自定义过滤器”?
具有 Spring Security 和 Java Config 的自定义身份验证提供程序
Spring security - 自定义 AuthenticationProvider 不起作用 - Java Config