• 01. spring-security 初体验


    01. Spring Security

    参考:

    https://blog.csdn.net/qq_36095679/article/details/92625701

    https://blog.csdn.net/yuanlaijike/article/details/80249235

    #核心组件

    • SecurityContextHolder

      SecurityContextHolder它持有的是安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权等等,这些都被保存

      SecurityContextHolder它持有的是安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权等等,这些都被保存

    • SecurityContext

      持有Authentication对象和其他可能需要的信息

    • AuthenicationManager

      AuthenticationManager 其中可以包含多个AuthenticationProvider

    • providerManager

      ProviderManager对象为AuthenticationManager接口的实现类

    • AuthenticationProvider

      AuthenticationProvider 主要用来进行认证操作的类 调用其中的authenticate()方法去进行认证操作

    • Authentication

      Authentication:Spring Security方式的认证主体

      鉴权对象,该对象主要包含了用户的详细信息(UserDetails)和用户鉴权时所需要的信息,如用户提交的用户名密码、Remember-me Token,或者digest hash值等

    • GrantedAuthority

      GrantedAuthority:对认证主题的应用层面的授权,含当前用户的权限信息,通常使用角色表示

    • UserDetails

      UserDetails:构建Authentication对象必须的信息,可以自定义,可能需要访问DB得到

      这个接口规范了用户详细信息所拥有的字段,譬如用户名、密码、账号是否过期、是否锁定等。在Spring Security中,获取当前登录的用户的信息,一般情况是需要在这个接口上面进行扩展,用来对接自己系统的用户

    • UserDetailService

      UserDetailsService:通过username构建UserDetails对象,通过loadUserByUsername根据userName获取UserDetail对象 (可以在这里基于自身业务进行自定义的实现 如通过数据库,xml,缓存获取等)

      通过扩展这个接口来显示获取我们的用户信息,用户登陆时传递的用户名和密码也是通过这里这查找出来的用户名和密码进行校验,但是真正的校验不在这里,而是由AuthenticationManager以及AuthenticationProvider负责的,需要强调的是,如果用户不存在,不应返回NULL,而要抛出异常UsernameNotFoundException

    #UserDetailsService

    @Service("cusUserDetails")
    public class UserDetailsServiceImpl implements UserDetailsService {
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private RoleMapper roleMapper;
        @Autowired
        private UserRoleMapper userRoleMapper;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            if (StringUtils.isEmpty(username)) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            UserDO user = userMapper
                    .selectOne(new QueryWrapper<UserDO>().eq("name", username));
            if (ObjectUtils.isEmpty(user)) {
                throw new UsernameNotFoundException("用户不存在");
            }
            //根据用户id查询用户对应的角色id
            List<UserRole> userRoles = userRoleMapper
                    .selectList(new QueryWrapper<UserRole>().eq("user_id", user.getId()));
            List<GrantedAuthority> authorities = new ArrayList<>();
            for (UserRole userRole : userRoles) {
                //根据用户角色id查询角色
                Integer roleId = userRole.getRoleId();
                Role role = roleMapper.selectById(roleId);
                //添加用户权限
                authorities.add(new SimpleGrantedAuthority(role.getName()));
            }
            return new User(user.getName(), user.getPassword(), authorities);
        }
    }
    

    #配置类

    @Configuration
    //开启@PreAuthorize()
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserDetailsService userDetailsService;
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/login").permitAll()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/login")
                    .defaultSuccessUrl("/").permitAll()
                    //如果不配置默认/login,post作为检验
    //                .loginProcessingUrl("/");
                    .and()
                    //默认/logout
                    .logout().permitAll();
        }
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring()
                    .antMatchers("/css/**","/js/**","/home.html");
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
                //自定义加密, 明文加密明文返回
                @Override
                public String encode(CharSequence charSequence) {
                    return charSequence.toString();
                }
    
                @Override
                public boolean matches(CharSequence charSequence, String s) {
                    return s.equals(charSequence.toString());
                }
            });
        }
    }
    

    #controller

    @Slf4j
    @Controller
    public class LoginController {
        @RequestMapping("/")
        public String showHome() {
            //获取当前登录用户的用户名
            String name = SecurityContextHolder.getContext().getAuthentication().getName();
            log.info("当前登陆用户:" + name);
            return "home";
        }
    
        @GetMapping("/login")
        public String toLogin(){
            //返回静态页面使用redirect
            return "login";
        }
        //这里对应数据库中的权限是spring规定的格式ROLE_xxx
        @ResponseBody
        //需要添加@EnableGlobalMethodSecurity(prePostEnabled = true)
        //@PreAuthorize用于判断用户是否有指定的权限, 没有就不能访问
        @PreAuthorize("hasRole('ROLE_ADMIN')")
        @GetMapping("/admin")
        public String printAdmin(){
            return "如果你看见这句话,说明你有ROLE_ADMIN角色";
        }
    
        @RequestMapping("/user")
        @ResponseBody
        @PreAuthorize("hasRole('ROLE_USER')")
        public String printUser() {
            return "如果你看见这句话,说明你有ROLE_USER角色";
        }
    
        @GetMapping("/logout")
        public String hello(){
            return "redirect:/login";
        }
    }
    

    #html

    <!DOCTYPE html >
    <html xmlns:th="https://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
        <link rel="stylesheet" th:href="@{/css/login.css}" type="text/css">
    </head>
    <body>
    <form class="login-page" th:action="@{/login}" method="post">
        <div class="form">
            <h3>账户登录</h3>
            <input type="text" placeholder="用户名" name="username" required="required"/>
            <input type="password" placeholder="密码" name="password" required="required"/>
            <button type="submit">登录</button>
        </div>
    </form>
    </body>
    </html>
    
    <html lang="en" xmlns:th="https://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>home</title>
    </head>
    <body>
    <h1>登陆成功</h1>
    <a th:href="@{/admin}">检测ROLE_ADMIN角色</a>
    <a th:href="@{/user}">检测ROLE_USER角色</a>
    <button onclick="window.location.href='/logout'">退出登录</button>
    </body>
    </html>
    
  • 相关阅读:
    jvm参数陷阱
    concurrent mode failure
    17.Quick QML-SpinBox
    16.Quick QML-ButtonGroup、RadioButton、CheckBox
    15.Quick QML-TextEdit和TextArea
    14.Quick QML-TextInput和TextField详解
    13.Quick QML-RowLayout、ColumnLayout、GridLayout布局管理器介绍、并通过GridLayout设计的简易网站导航界面
    9.qml-property自定义属性
    macOS 系统安装Maven教程
    macOS系统上 为Github 托管项目的访问添加SSH keys
  • 原文地址:https://www.cnblogs.com/kikochz/p/12890909.html
Copyright © 2020-2023  润新知