同过查询数据库进行用户匹配 (Mybatis-Plus)
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 调用userMapper方法查询数据库
QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",username);
UserEntity userEntity = userMapper.selectOne(queryWrapper);
if (userEntity==null){
//数据库没有当前用户,认证失败
throw new UsernameNotFoundException("用户不存在!");
}
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User(userEntity.getUsername(),new BCryptPasswordEncoder().encode(userEntity.getPassword()),auths);
}
}
mapper
@Mapper
public interface UserMapper extends BaseMapper<UserEntity> {
}
mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.security.mapper.UserMapper">
</mapper>
用户实体类
@Data
@TableName("users")
public class UserEntity {
private Integer id;
private String username;
private String password;
}
=========================================================================
自定义设置登录页面/访问路径过滤
@Configuration
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //自定义自己编写的界面
.loginPage("/login.html") //登陆页面设置
.loginProcessingUrl("/user/login") //登录时访问路径
.defaultSuccessUrl("/security/http").permitAll() //登录成功访问路径
.and().authorizeRequests()
.antMatchers("/","/security/add","/user/login").permitAll() //设置可以直接访问不需要认证的路径
.anyRequest().authenticated()
.and().csrf().disable(); //关闭csrf防护
}
}
基于角色或权限进行访问控制
方法一:hasAuthority
如果当前主体具有指定的权限,则返回true,否则返回false
1.在配置类中为访问路径设置权限
//当前登录用户,只有具有admins权限才可访问该路径 .antMatchers("/security/http").hasAuthority("admins")2.在UserDetailsService中,为返回user对象设置权限
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins"); return new User(userEntity.getUsername(),new BCryptPasswordEncoder().encode(userEntity.getPassword()),auths);方法二:hasAnyAuthority
如果当前主体具有任一(多个权限)权限,则返回true,否则返回false
1.在配置类中为访问路径设置权限
.antMatchers("/security/chen").hasAnyAuthority("admins,manager")2.在UserDetailsService中,为返回user对象设置权限
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins"); return new User(userEntity.getUsername(),new BCryptPasswordEncoder().encode(userEntity.getPassword()),auths);方法三:hasRole
.antMatchers("/security/http").hasRole("role")List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_role"); return new User(userEntity.getUsername(),new BCryptPasswordEncoder().encode(userEntity.getPassword()),auths);方法四:hasAnyRole 多个角色
.antMatchers("/security/chen").hasAnyRole("role,manager")List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_role"); return new User(userEntity.getUsername(),new BCryptPasswordEncoder().encode(userEntity.getPassword()),auths);
当前用户没有访问该接口的权限(403)
自定义403页面
//配置,没有权限访问跳转自定义页面 http.exceptionHandling().accessDeniedPage("/unauth.html");
注解的使用
1.@Secured
1.启动类(配置类)开启注解
@EnableGlobalMethodSecurity(securedEnabled = true) //开启注解2.controller中添加注解
@ApiOperation("权限管理") @Secured({"ROLE_sale","ROLE_manager"}) @GetMapping("/update")3.配置类设置用户权限(如上操作)
2.@ PreAuthorize 方法前进行验证
1.启动类(配置类)开启注解
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) //开启注解2.controller中添加注解
@PreAuthorize("hasAnyAuthority('admins')")
3.@PostAuthorize 方法后进行验证
4.@PostFilter
5.@PreFilter
用户注销
1.配置类添加 //注销 http.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html").permitAll();测试:
1.修改配置类,登录成功后跳转到成功页面
.defaultSuccessUrl("/success.html").permitAll() //登录成功访问路径2.在成功页面添加超链接,设置退出路径
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登录成功</h1> <a href="/logout" style="color: brown">退出登录</a> </body> </html>