目的:登录用户名密码 获取到数据库中的用户 、密码以及权限,根据不同用户以及不同权限,可访问的路径权限也受到限制。
这边用一个小的案例,来体现大体的security权限思想。
1、首先先根据数据库 创建实体类User 实现UserDetails这个接口
/** * @Author fei * @Date 2021/1/3 7:42 下午 * * 如果自己要在数据库中加载用户,那user类就要实现UserDetails这个接口 然后实现里面的方法 */ public class User implements UserDetails { private Integer id; private String username; private String password; private Boolean enabled; private Boolean locked; private List<Role> roleList; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Override public String getUsername() { return username; } /** * isAccountNonExpired 表示账户是否未过期 * 返回true 表示 是没有过期 * @return */ @Override public boolean isAccountNonExpired() { return true; } /** * isAccountNonLocked 账户是否未锁定 * @return */ @Override public boolean isAccountNonLocked() { //因为这边 是 账户是否未被锁定,而数据库中是没有锁定为false 所以这里要取反 return !locked; //在数据库中正好有这个字段,就不要写死了 返回locked就行。这个相当于get方法,所以要将原来该字段的get方法删掉,否则就重复了。 } /** * isCredentialsNonExpired 密码是否未过期 * @return */ @Override public boolean isCredentialsNonExpired() { return true; //没有过期 } /** * 是否可用 * @return */ @Override public boolean isEnabled() { return enabled;//本身也有这个字段,则直接返回。去掉原有的get方法。 } public void setUsername(String username) { this.username = username; } /** * 这个集合是用来返回用户的所有角色。 * @return */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); for (Role role : roleList) { //返回的所有角色必须前面有 ROLE_ ,没有回报错,如果数据库中本身就是以这个开头,就可以不用写 authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName())); } return authorities; } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // public Boolean getEnabled() { // return enabled; // } public void setEnabled(Boolean enabled) { this.enabled = enabled; } // public Boolean getLocked() { // return locked; // } public void setLocked(Boolean locked) { this.locked = locked; } public List<Role> getRoleList() { return roleList; } public void setRoleList(List<Role> roleList) { this.roleList = roleList; } }
2、在Service层同样要 实现UserDetailsService
/** * @Author fei * @Date 2021/1/3 8:43 下午 * * 同样userService也要实现UserDetailsService,同时实现里面的方法。因为这边要执行登录的逻辑 */ @Service public class UserService implements UserDetailsService { @Autowired UserMapper userMapper; /** * 这个方法就是根据用户名来查询用户,有了这个方法都是走这个方法,找不到则抛出异常 * @param username * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userMapper.loadUserByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在!"); } //如果不是空 则需要查询该用户角色 user.setRoleList(userMapper.getUserRolesById(user.getId())); return user; //查到之后就返回,至于填的密码,和他本身的密码,由security自己去比较。我们只要查到就行,查不到就抛异常。 } }
3、 数据库xml
<mapper namespace="com.ppf.securitydb.mapper.UserMapper"> <select id="loadUserByUsername" resultType="com.ppf.securitydb.bean.User"> select * from user where username = #{username} </select> <select id="getUserRolesById" resultType="com.ppf.securitydb.bean.Role"> select * from role where id in(select rid from user_role where uid = #{id}) //user_role是关联用户所对应的角色的表 </select> </mapper>
4、 配置securityConfig 这边很重要
/** * @Author fei * @Date 2021/1/4 10:26 下午 */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserService userService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService); //这边表示用上数据库里面的用户 } @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/dba/**").hasRole("dba") .antMatchers("/admin/**").hasRole("admin") .antMatchers("/user/**").hasRole("user") .anyRequest().authenticated() .and() .formLogin() .permitAll() .and() .csrf().disable(); } }
5、Controller层 写几个方法,来测试权限
/** * @Author fei * @Date 2021/1/4 10:36 下午 */ @RestController public class HelloController { @GetMapping("/hello") public String hello(){ return "hello security!"; } @GetMapping("/dba/hello") public String dba(){ return "hello dba!"; } @GetMapping("/admin/hello") public String admin(){ return "hello admin!"; } @GetMapping("/user/hello") public String user(){ return "hello user!"; } }
6、 最后得出结果,只有所对应用户的角色 才能进入相应的路径。
比如 admin 数据库中密码为 $2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq (实际解密后123)
角色只是为admin 所以只能 /admin/hello 其他用户的和dba的无权进入。