微人事——Spring Security权限管理(一)

权限管理(一)

我用的是Spring Security权限管理,分为“认证”以及“验证”。
“认证”就是登陆,“验证”就是根据权限授予一定的操作,也就是权限。

Spring Security大致的过程就是这样
在这里插入图片描述
这个图片不是我做的,是另一个博主做的我觉得很不错。
原地址: https://blog.csdn.net/zhaoxichen_10/article/details/88713799.

(一)数据库设计

数据库设计

权限管理系统涉及到了三个数据库。

  • hr数据库是存储账户信息
    hr数据库
  • menu是权限管理数据库
    权限管理数据库
  • role是角色数据库
    角色数据库

(二)认证过程

认证过程就是用户根据hr中的username和password来登陆系统。
认证过程和menu类无关,不涉及menu类中的方法

1、Hr实体类
  • 如果我们需要从数据库里面加载用户,那么我们在定义用户的时候就要实现一个接口UserDetails
  • UserDetails相当于是一个规范,所有人都得实现它,这样的话以后我要获取用户名我就知道就是username,我要获取密码就是password
@Data
@Entity
@Table(name = "hr")
public class Hr implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id ;
    private String name;
    private String phone;
    private String telephone;
    private String address;
    private Boolean enabled;
    private String username;
    private String password;
    private String userface;
    private String remark;

    @ManyToMany(cascade = {CascadeType.REFRESH},fetch=FetchType.EAGER)
    @JoinTable(name = "hr_role", joinColumns = {@JoinColumn(name ="hrid" )}, inverseJoinColumns = { @JoinColumn(name = "rid") })
    private List<Role> roles ;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Hr hr = (Hr) o;
        return Objects.equals(username, hr.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(username);
    }

    //返回分配给用户的角色列表
    @Override
    @JsonIgnore
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>(roles.size());
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        return authorities;
    }

    //账户是否过期
    @Override
    public boolean isAccountNonExpired() {
        return  true;
    }

    //账户是否锁定
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    //密码是否过期
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    //账户是否激活
    @Override
    public boolean isEnabled() {
        return true;
    }

  
2、关于JPA的多表联查

Hr和Role的关系是单向多对多

	@ManyToMany(cascade = {CascadeType.REFRESH},fetch=FetchType.EAGER)
	@JoinTable(name = "hr_role", joinColumns = {@JoinColumn(name ="hrid" )}, inverseJoinColumns = { @JoinColumn(name = "rid") })
    private List<Role> roles ;
  • 单向多对多就是生成一个中间表,多对多关联映射需要新增加一张表(hr_role)才完成基本映射
  • JoinTable是中间表表名
  • joinColumns指定中间表中关联自己ID的字段
  • joinColumn是列名
  • inverseJoinColumns表示中间表中关联对方ID的字段
    关联表
    hrid代表hr的id,rid表示Role中的id
3、HrService类
public interface HrRepository extends JpaRepository<Hr,Integer> {
    public Hr findByUsername(String username);
}

创建HrService类,并实现UserDetailsService类,重写该类的loadUserByUsername方法

@Service
public class HrService implements UserDetailsService {

    @Autowired
    HrRepository hrRepository;
   
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Hr hr = hrRepository.findByUsername(s);
        if (hr == null){
            throw new UsernameNotFoundException("用户名不对");
        }
        return hr;
    }
}
4、配置WebConfig类

webconfig类需要继承WebSecurityConfigurerAdapter类

@Configuration
public class webSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    HrService hrService;
   

    //明文显示密码
    @Bean
    public CustomPasswordEncoder passwordEncoder() {
        return new CustomPasswordEncoder();
    }

    //定义认证规则
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.userDetailsService(hrService)
              .passwordEncoder(new CustomPasswordEncoder());

  
    }

由于spring5的内置加密方法是BCrypt,为了测试简单,我设置了明文加密

/**
 * 明文显示密码
 */
public class CustomPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.equals(charSequence.toString());
    }
}
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //剩下的其他请求都是登陆之后就能访问的
          		.anyRequest().authenticated()
                //单表登陆
                .and().formLogin()
                //修改默认登陆的username
                .usernameParameter("username")
                //修改默认登陆的password
                .passwordParameter("password")
                //处理单表登陆的url路径
                .loginProcessingUrl("/doLogin")
                //默认看到的登录页面
                .loginPage("/login")
                //登陆成功的处理
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        //如果登陆成功就返回一段json
                        resp.setContentType("application/json;charset=utf-8");
                        //这是往出写的
                        PrintWriter out = resp.getWriter();
                        //登陆成功的hr对象
                        Hr hr = (Hr) authentication.getPrincipal();
                        RespBean ok = RespBean.ok("登陆成功",hr);
                        //把hr写成字符串
                        String s = new ObjectMapper().writeValueAsString(ok);
                        //把字符串写出去
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                })
                //登陆失败的处理
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
                        //如果登陆失败就返回一段json
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        RespBean respBean = RespBean.error("登陆失败!");
                        if (e instanceof LockedException){
                            respBean.setMsg("账户被锁定,请联系管理员!");
                        }else if (e instanceof CredentialsExpiredException){
                            respBean.setMsg("密码过期,请联系管理员!");
                        }else if (e instanceof AccountExpiredException){
                            respBean.setMsg("账户过期,请联系管理员!");
                        }else if (e instanceof DisabledException){
                            respBean.setMsg("账户被禁用,请联系管理员!");
                        }else if (e instanceof  BadCredentialsException){
                            respBean.setMsg("用户名或者密码输入错误,请联系管理员!");
                        }
                        out.write(new ObjectMapper().writeValueAsString(respBean));
                        out.flush();
                        out.close();
                    }
                })
                //跟登陆相关的接口就能直接访问
                .permitAll()
                .and()
                .logout()
                //注销成功后的回调
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(RespBean.ok("注销成功!")));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll()
                .and()
                //关闭csrf攻击
                .csrf().disable();
    }
5、postman测试

在这里插入图片描述
在这里插入图片描述
到这里认证就完成了,接下来就是权限了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值