权限框架SpringSecurity实用总结

1.数据库结构图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2. SpringSecutiryConfiguration 此框架核心配置类

package com.pug.security;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SpringSecutiryConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;
    @Autowired
    private MyLoginSuccessHandler myLoginSuccessHandler;
    @Autowired
    private MyLoginFailHandler myLoginFailHandler;
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    // 认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 1:基于接口认证
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    // 授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
http
// 所有的请求开始接受认证处理
.authorizeRequests()
//不需要被认证
.antMatchers("/index", "/toLogin", "/fail", "/logout", "/nopermission")
// permitAll 放行不认证 只针对上permitAll()自身方法前定义的路径
.permitAll()
//.antMatchers("/user/list").hasRole("Admin")
//.antMatchers("/user/search").hasRole("User")
//.antMatchers("/user/get/**").hasAnyRole("User", "Admin")
//.antMatchers("/user/get/**").hasAuthority("user:list")
//所有请求都必须被认证,必须登录后被访问
.anyRequest().authenticated()
// 下一个配置   如果出现权限不足,403错误处理
.and().exceptionHandling().accessDeniedHandler(myAccessDeniedHandler)
// 下一个配置
.and().formLogin().loginProcessingUrl("/login")
.loginPage("/toLogin").usernameParameter("username")
.passwordParameter("password").successHandler(myLoginSuccessHandler)
.failureHandler(myLoginFailHandler).and().rememberMe()
.rememberMeParameter("remember-me").rememberMeCookieName("ksd-remember-me")
.tokenValiditySeconds(1800)
// 下一个配置
         .and().logout().logoutSuccessHandler(myLogoutSuccessHandler)
         .deleteCookies("ksd-remember-me", "JSESSIONID")
           .and().csrf().disable();


}


// 放行资源
// 写到这里的资源放行,是不进入过滤器链的
@Override
public void configure(WebSecurity webSecurity) throws Exception {
   webSecurity.ignoring()
   .antMatchers
   ("/index.html", "/js/**", "/css/**", "/fonts/**", "/images/**", "/img/**");
}


@Bean
public PasswordEncoder passwordEncoder() {
   return new BCryptPasswordEncoder();
}

//    public static void main(String[] args) {
//        System.out.println(new BCryptPasswordEncoder().encode("123456"));
//    }
}

.antMatchers( “/toLogin”, “/fail”, “/logout”, “/nopermission”)
.and().formLogin().loginProcessingUrl("/login").loginPage("/toLogin")
所有request请求都需要被认证,除了 “/toLogin”, “/fail”, “/logout”, "/nopermission"这四个请求地址,
都会被重定向到http://localhost:8787/toLogin中!!!

控制层!!!

@Controller
public class LoginController {

    @RequestMapping("/toLogin")
    public String login() {
        return "login";
    }

}

login.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Please sign in</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
</head>
<body>
<div class="container">
    <form class="form-signin" method="post" action="/login">
        <h2 class="form-signin-heading" style="text-align:center ;">请登录</h2>
        <p>
            <label for="username" class="sr-only">账号</label>
            <input type="text" id="username" name="username"  class="form-control" placeholder="用户名" required autofocus>
        </p>
        <p>
            <label for="password" class="sr-only">密码</label>
            <input type="password" id="password" name="password" class="form-control" placeholder="密码" required>
        </p>
        <p><input type='checkbox' name='remember-me' checked/> 记住我</p>
        <button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
    </form>
</div>
</body></html>

rememberMe()
.rememberMeParameter(“remember-me”).rememberMeCookieName(“ksd-remember-me”)
.tokenValiditySeconds(1800)

在这里插入图片描述
BCryptPasswordEncoder()加密的!!!

public static void main(String[] args) {
   System.out.println(new BCryptPasswordEncoder().encode("123456"));}

$2a 10 10 10JvQfsMscgToXnjzbHt89.ujHI5MFwTRFbXvVDo43046r2/AR0s1ey

在这里插入图片描述
.authorizeRequests()
//不需要被认证
.antMatchers( “/toLogin”, “/fail”, “/logout”, “/nopermission”)
// permitAll 放行不认证 只针对上permitAll()自身方法前定义的路径
.permitAll()
点击登录,必须认证!!!!
// 认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 1:基于接口认证
auth.userDetailsService(userDetailsService).(passwordEncoder());
}
自定义一个业务类,结合MybatisPlus,最关键是实现了UserDetailsService接口!!!

package com.pug.service.security;

@Service
@Slf4j
public class LoginUserServiceImpl extends 
ServiceImpl<SysLoginUserMapper, SysLoginUser> 
implements UserDetailsService, ILoginUserService {


    @Override
    public UserDetails loadUserByUsername(String username)
     throws UsernameNotFoundException {
        // 1: 设定查询条件
        LambdaQueryWrapper<SysLoginUser> queryWrapper = new LambdaQueryWrapper<>();
        // 2: 设置数据的用户名和输入用户进行where匹配
        queryWrapper.eq(SysLoginUser::getUsername, username);
        // 3: 执行查询
        SysLoginUser sysLoginUser = this.getOne(queryWrapper);
        // 4: 如果你查询用户不等于null
        if (sysLoginUser != null) {
            // 5:根据用户查询对应角色
List<SysRole> roleList = this.baseMapper.findSysRoleByUserId(sysLoginUser.getId());
// 6:根据用户查询对应权限
List<SysPermission> permissionList = this.baseMapper
.findByAdminUserId(sysLoginUser.getId());
// 7: 组装角色权限数据
// 7-1: 注意角色必须在这里增加ROLE_ 。不要在数据库里添加。因为根据灵活、
List<SimpleGrantedAuthority> roleAuthoritys =
 roleList.stream().map(role -> "ROLE_" + role.getName())
        //.map(SimpleGrantedAuthority::new)
        .map(str -> new SimpleGrantedAuthority(str))
        .collect(Collectors.toList());

            // 8: 组装用户权限数据数据 。
            // 8-1: 这里是根据权限名称
            // 8-2: 这里是根据权限名称 + URL
 List<SimpleGrantedAuthority> permissionAuthoritys = permissionList.stream()
 .map(permission -> permission.getName())
          //.map(SimpleGrantedAuthority::new)
          .map(str -> new SimpleGrantedAuthority(str))
          .collect(Collectors.toList());
  // 9:组合
  Set<GrantedAuthority> authorities =
   new HashSet<>(roleList.size() + permissionList.size());
  authorities.addAll(roleAuthoritys);
  authorities.addAll(permissionAuthoritys);
  // 10: 把用户查询的账号和密码,以及权限,和角色赋予SpringSecurity的UserDetails实现者User
  LoginUser loginUser =
   new LoginUser(sysLoginUser, roleList.stream().collect(Collectors.toSet()),
          permissionList.stream().collect(Collectors.toSet()), authorities);
  loginUser.setOs("window10");
  loginUser.setIp("127.0.0.1");
  loginUser.setIpLocation("guangzhou");
  loginUser.setLoginTime(new Date().getTime()+"");
  return loginUser;
} else {
  throw new RuntimeException("用户名和密码有误!!!");
}
}
}

<?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.pug.mapper.SysLoginUserMapper">
    <!--问:List<SysRole> 为什么可以使用SysRole-->
    <select id="findSysRoleByUserId" resultType="com.pug.pojo.SysRole">
       SELECT
           sr.*
        FROM
            sys_role_user sru
        LEFT JOIN sys_role sr ON sr.id = sru.sys_role_id
        WHERE
            sru.sys_user_id = #{userId}
    </select>


    <select id="findByAdminUserId" resultType="com.pug.pojo.SysPermission">
        SELECT
            p.*
        FROM
            sys_role_user sru
                LEFT JOIN Sys_Role r ON sru.Sys_Role_id = r.id
                LEFT JOIN Sys_permission_role spr ON spr.role_id = r.id
                LEFT JOIN Sys_permission p ON p.id = spr.permission_id
        WHERE
            sru.sys_user_id = #{userId}
    </select>

</mapper>

在这里插入图片描述
.and().formLogin().loginProcessingUrl("/login").loginPage("/toLogin").usernameParameter(“username”).passwordParameter(“password”).successHandler(myLoginSuccessHandler).failureHandler(myLoginFailHandler).

认证成功的话 MyLoginSuccessHandler myLoginSuccessHandler

@Component
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {


    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        //User user = (User) authentication.getPrincipal();
        //request.getSession().setAttribute("sessionuser", user);
        // 生成token
        response.sendRedirect("/index");
    }
}
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <h1>我是后台首页</h1>
        <h3>你当前登录的信息是:{{user.username}} === {{roles}}</h3>
        <div>{{permissions}}</div>
        <a href="/logout">退出</a>
        <div>
            <a href="/user/get/1">查询用户</a>&nbsp;&nbsp;&nbsp;
            <a href="/user/search">搜索用户</a>&nbsp;&nbsp;&nbsp;
            <a href="/user/list">用户列表</a>
        </div>
    </div>

    <script src="/js/vue.min.js"></script>
    <script src="/js/axios.min.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                user:{},
                roles:[],
                permissions:[],
            },
            created(){
                this.loadUser();
            },
            methods:{
                loadUser(){
                    axios.post("/username").then(res=>{
                        this.user = res.data;
                        this.roles = this.user.roles.map(role=>role.title).join(",");
                        this.permissions = this.user.permissions;
                    })
                }
            }
        })
    </script>

</body>
</html>

认证失败的话MyLoginFailHandler myLoginFailHandler

@Component
@Slf4j
public class MyLoginFailHandler implements AuthenticationFailureHandler {


    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        log.info("失败的原因是:{}", exception.getMessage());
        // 生成token
        response.sendRedirect("/fail?msg="+exception.getMessage());
    }
}

最核心的是自己改写了User类如下:

public class LoginUser implements UserDetails {

    private Long userId;
    private String username;
    private String ip;
    private String ipLocation;
    private String os;
    private String loginTime;
    private SysLoginUser sysLoginUser;
    private Set<SysRole> roles;
    private Set<SysPermission> permissions;
    private Set<GrantedAuthority> authorities;

    public LoginUser(SysLoginUser sysLoginUser,Set<SysRole> roles,Set<SysPermission> permissions,
                     Set<GrantedAuthority> authorities){
        this.userId = sysLoginUser.getId();
        this.username = sysLoginUser.getUsername();
        this.sysLoginUser = sysLoginUser;
        this.roles = roles;
        this.permissions = permissions;
        this.authorities = authorities;
    }


    @JsonIgnore
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @JsonIgnore
    @Override
    public String getPassword() {
        return sysLoginUser.getPassword();
    }

    @Override
    public String getUsername() {
        return sysLoginUser.getUsername();
    }

    private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<>(new LoginUser.AuthorityComparator());
        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }
        return sortedAuthorities;
    }


    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return true;
    }

    private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {

        private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

        @Override
        public int compare(GrantedAuthority g1, GrantedAuthority g2) {
            if (g2.getAuthority() == null) {
                return -1;
            }
            if (g1.getAuthority() == null) {
                return 1;
            }
            return g1.getAuthority().compareTo(g2.getAuthority());
        }

    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getIpLocation() {
        return ipLocation;
    }

    public void setIpLocation(String ipLocation) {
        this.ipLocation = ipLocation;
    }

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }

    public String getLoginTime() {
        return loginTime;
    }

    public void setLoginTime(String loginTime) {
        this.loginTime = loginTime;
    }

    @JsonIgnore
    public SysLoginUser getSysLoginUser() {
        return sysLoginUser;
    }

    public void setSysLoginUser(SysLoginUser sysLoginUser) {
        this.sysLoginUser = sysLoginUser;
    }

    public Set<SysRole> getRoles() {
        return roles;
    }

    public void setRoles(Set<SysRole> roles) {
        this.roles = roles;
    }

    public Set<SysPermission> getPermissions() {
        return permissions;
    }

    public void setPermissions(Set<SysPermission> permissions) {
        this.permissions = permissions;
    }

    public void setAuthorities(Set<GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "LoginUser{" +
                "userId=" + userId +
                ", ip='" + ip + '\'' +
                ", ipLocation='" + ipLocation + '\'' +
                ", os='" + os + '\'' +
                ", loginTime='" + loginTime + '\'' +
                ", sysLoginUser=" + sysLoginUser +
                ", roles=" + roles +
                ", permissions=" + permissions +
                ", authorities=" + authorities +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        LoginUser loginUser = (LoginUser) o;
        return Objects.equals(userId, loginUser.userId) && Objects.equals(ip, loginUser.ip) && Objects.equals(ipLocation, loginUser.ipLocation) && Objects.equals(os, loginUser.os) && Objects.equals(loginTime, loginUser.loginTime) && Objects.equals(sysLoginUser, loginUser.sysLoginUser) && Objects.equals(roles, loginUser.roles) && Objects.equals(permissions, loginUser.permissions) && Objects.equals(authorities, loginUser.authorities);
    }

    @Override
    public int hashCode() {
        return Objects.hash(userId, ip, ipLocation, os, loginTime, sysLoginUser, roles, permissions, authorities);
    }
}

在这里插入图片描述
配置类方式
//.antMatchers("/user/list").hasRole(“User”)
//.antMatchers("/user/search").hasRole(“Admin”)
//.antMatchers("/user/get/**").hasAuthority(“user:list”)

注解方式:

@RestController
public class UserController {

    @Autowired
    private ILoginUserService loginUserService;

    @GetMapping("/user/get/{id}")
    @PreAuthorize("hasAnyRole('Admin','User')")
    public SysLoginUser getUser(@PathVariable("id") Long id) {
        return loginUserService.getById(id);
    }

    @GetMapping("/user/list")
    @PreAuthorize("hasRole('User')")
    public List<SysLoginUser> listuser() {
        return loginUserService.list();
    }

    @GetMapping("/user/search")
    @PreAuthorize("hasAuthority('course:list')")
    public List<SysLoginUser> searchuser() {
        return loginUserService.list();
    }
}

admin用户点击搜索:
在这里插入图片描述

// 下一个配置 如果出现权限不足,403错误处理
.and().exceptionHandling().accessDeniedHandler(myAccessDeniedHandler)

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {

   @Override
   public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
//      response.setStatus(HttpServletResponse.SC_FORBIDDEN);
//      response.setHeader("Content-Type", "application/json;charset=utf-8");
//      PrintWriter out = response.getWriter();
//      out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员!\"}");
//      out.flush();
//      out.close();

       response.sendRedirect("/nopermission");
   }
}

nopermission.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>没权限</title>
</head>
<body>
    <h1>没有权限,请联系管理员</h1>
    <a href="/">返回首页</a>
</body>
</html>

难点:
1.SpringSecutiryConfiguration 配置类的书写
2.两个业务层代码的书写
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值