• 【Java】Spring scruity 简单上手


    1、引入依赖

        
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-securityartifactId>
            dependency>
    	
            <dependency>
                <groupId>com.github.pengglegroupId>
                <artifactId>kaptchaartifactId>
                <version>2.3.2version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、编写配置类OaSecurityConfig

    package com.manager.oa.config;
    
    import com.manager.oa.filter.CaptchaFilter;
    import com.manager.oa.filter.ValidateException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-17
     */
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 启用权限验证
    public class OaSecurityConfig extends WebSecurityConfigurerAdapter {
        /**
         * 配置验证码过滤器
         *
         * @return
         */
        @Bean
        public CaptchaFilter captchaFilter() {
            return new CaptchaFilter();
        }
    
        /**
         * spring security 配置类
         *
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 验证码过滤器,加在了用户密码过滤器之前
            http.addFilterBefore(captchaFilter(), UsernamePasswordAuthenticationFilter.class);
            http.formLogin()
                    .loginPage("/portal/login") //指定自己的登录页面
                    .loginProcessingUrl("/portal/tologin")  //与登录表单的action保持一致
                    // .successForwardUrl("/portal/")
                    .successHandler(new AuthenticationSuccessHandler() {  // 成功定制
                        @Override
                        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                            response.sendRedirect("/portal/"); // 从定向
                            //  response.getWriter().print(""); // 返回前端JSON
                        }
                    })
                    // .failureForwardUrl("/portal/login") // 失败后的url
                    .failureHandler(authenticationFailureHandler()) // 失败后进行异常处理
                    .usernameParameter("account")
                    .passwordParameter("password")
                    .and()
                    .authorizeRequests() //下面的都是授权的配置 3
                    .antMatchers("/portal/login", "/css/**", "/images/*", "/captcha").permitAll()
                    .anyRequest() //任何请求 4
                    .authenticated()//要求认证
                    .and().csrf().disable(); //禁用csrf攻击解决方案
    
            http.headers().frameOptions().disable()
                    .and()
                    .logout();
            // 在没有权限访问时,SpriSecurity会抛出AccessDeniedException,为了处理该异常,使用以下配置
            http.exceptionHandling().accessDeniedHandler((req, resp, e) -> {
                resp.sendRedirect("/portal/noperm");
            });
            // 在登录成功之后,如果会话失效(默认30分钟或手动删除Cookie),默认跳到登录界面,如果需要自定义,
            http.exceptionHandling().authenticationEntryPoint((req, resp, e) -> {
                resp.sendRedirect("/portal/nosession");
            });
    
        }
    
        @Autowired
        private UserDetailsService userDetailsService;
    
        /**
         * 异常处理Bean的配置
         * 由于框架在验证密码和用户名时,做了相关的模糊处理,默认提示“用户名或密码错误”,
         * 需要将HideUserNotFoundExceptions设置为false,就可以分别提示,用户名,密码错误;
         * 

    * 由于 new DaoAuthenticationProvider();之后,里面的属性都为空,需要重新将userDetailsService 设置进去 * * @return */ @Bean public DaoAuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); // 为了提供细致提示,设置Provider的hideUserNotFoundExceptions的属性为false daoAuthenticationProvider.setHideUserNotFoundExceptions(false); daoAuthenticationProvider.setUserDetailsService(userDetailsService); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); return daoAuthenticationProvider; } /** * 异常处理Bean * * @return */ @Bean public AuthenticationFailureHandler authenticationFailureHandler() { return (req, resp, exception) -> { if (exception instanceof UsernameNotFoundException) { req.setAttribute("msg", "账号不存在"); } else if (exception instanceof BadCredentialsException) { req.setAttribute("msg", "密码不正确"); } else if (exception instanceof ValidateException) { req.setAttribute("msg", "验证码不正确"); } else { req.setAttribute("msg", "系统维护中"); } req.getRequestDispatcher("/portal/login").forward(req, resp); }; } /** * 密码加密 * * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    3、编写自己的OaUserDetailsService,实现框架的UserDetailsService
    如下:
    框架中的UserDetailsService,里面只有一个方法,功能是通过用户名来验证用户;
    如果找不到用户,或者用户不存在,则抛出UsernameNotFoundException
    所以我们需要实现该方法首先验证用户名是否正确
    在这里插入图片描述
    由于该方法需要返回一个UserDetails(框架中的);
    该UserDetails主要存在以下属性,显然,这些都是一些基本属性,由于我们还要做权限验证,这些属性是不够的,
    在这里插入图片描述
    在这里插入图片描述
    所以我们需要编写自己的user类,来实现该类,增强一些属性:
    编写:OaUser

    package com.manager.oa.pojo.oa;
    
    import lombok.Data;
    import lombok.Getter;
    import lombok.Setter;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    
    import java.util.Collection;
    
    /**
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-18
     */
    @Getter
    @Setter
    public class OaUser extends User {
        public OaUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
            super(username, password, authorities);
        }
    
        public OaUser(String username, String password, com.manager.oa.pojo.rbac.User user, Collection<? extends GrantedAuthority> authorities) {
            this(username, password, authorities);
            this.user = user;
        }
    	// 新增属性,返回自己的整个实体类中的所有属性
        private com.manager.oa.pojo.rbac.User user;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    由于麻烦。我直接新增了我自己的use实体类
    以下是我的User

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonIgnoreProperties(value = {"handler"})
    public class User {
        private Integer id;
        private String account; // 账号
        private String password; // 密码
        private String img;// 头像
        private Role role;// 角色
        private String state;// 状态
        private Integer roleId;// 角色ID
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    现在编写OaUserDetailsService,重新 loadUserByUsername 该方法返回的就是我们刚刚编写的OaUser 该类是实现了框架的UserDetails的;
    返回的参数作简要说明:
    第一个参数:username,就是我们需要验证的账号,也就是前端传过来的用户名
    第二个参数:password, 为数据库中查询到的该账号的密码
    第三个参数:data, 为需要返回的数据,(我这里直接返回数据库中user的实体类)
    第四个参数:list,为该用户的所有权限,为后面做权限验证准备

    package com.manager.oa.service.rbac.impl;
    
    import com.manager.oa.mapper.rbac.UserMapper;
    import com.manager.oa.pojo.oa.OaUser;
    import com.manager.oa.pojo.rbac.Permission;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-17
     */
    @Slf4j
    @Component
    public class OaUserDetailsService implements UserDetailsService {
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            //根据账号去查询用户信息,把用户的权限查出来
            log.debug("用户账号:{}", username);
            com.manager.oa.pojo.rbac.User user = new com.manager.oa.pojo.rbac.User();
            user.setAccount(username);
            List<com.manager.oa.pojo.rbac.User> users = userMapper.findUsersByCondition(user);
            if (users.size() == 0) {//避免空指针
                throw new UsernameNotFoundException("账号不存在");    //抛出异常
            }
            log.debug("数据库信息:{}", users.get(0));
            log.debug("用户权限信息:{}", users.get(0).getRole().getPermissions());
            List<SimpleGrantedAuthority> list = new ArrayList<>();
            for (Permission p : users.get(0).getRole().getPermissions()
            ) {
                //过滤父权限
                if (p.getPerPower() == null) {
                    continue;
                }
                SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(p.getIdentify());
                list.add(simpleGrantedAuthority);
            }
            return new OaUser(username, users.get(0).getPassword(), users.get(0), list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    以下是我的 UserMapper,由于我开始编写了一个多条件查询的方法,所以我直接用的是多条件查询,也可以写一个通过用户名查找信息的方法;

    /**
     * 多条件查询
     *
     * @param user
     * @return
     */
    @SelectProvider(type = UserSqlProvider.class, method = "select")
    @Results(
            {
                    @Result(column = "id", property = "id", id = true),
                    @Result(column = "account", property = "account"),
                    @Result(column = "password", property = "password"),
                    @Result(column = "img", property = "img"),
                    @Result(column = "state", property = "state"),
                    @Result(column = "role", property = "role", one = @One(select = "com.manager.oa.mapper.rbac.RoleMapper.findRoleById", fetchType = FetchType.LAZY)),
            }
    )
    List<User> findUsersByCondition(User user);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后是Role角色实体类:

    @Data // get set toString equals 等
    @AllArgsConstructor // 带参构造
    @NoArgsConstructor // 无参构造
    public class Role {
        private Integer id;
        private String name; //名称
        private String description;//描述
        private String state; // 状态
        private List<Permission> permissions; //权限集合
        private List<Menu> menus; // 菜单集合
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    RoleMapper中的用到的方法:

    /**
     * 通过ID查询
     *
     * @param id
     * @return
     */
    @Select("select * from rbac_roles where id=#{id}")
    @Results({
            @Result(column = "id",property = "id",id = true),
            @Result(column = "id", property = "permissions",many = @Many(select = "com.manager.oa.mapper.rbac.PermissionMapper.findByRoleId")),
            @Result(column = "id", property = "menus",many = @Many(select = "com.manager.oa.mapper.rbac.MenuMapper.findByRoleId")),
    
    })
    Role findRoleById(int id);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    其次是该查询方法中的查询权限和菜单的方法:

       /**
         * 通过角色ID查询权限
         *
         * @param roleId
         */
        @Select("SELECT * from rbac_permission p,rbac_role_power r WHERE p.id=r.power and role=#{roleId}")
        List<Permission> findByRoleId(int roleId);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
       /**
         * 通过角色ID查询菜单
         *
         * @param roleId
         */
        @Select("SELECT * from rbac_menus m,rbac_role_menu r WHERE m.id=r.menu and role=#{roleId} and state='y'")
        List<Menu> findByRoleId(int roleId);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    完成上面我们就对前端传过来的账号密码做了验证,但是还有验证码没有验证,所以还需要编写验证码过滤器,该过滤器是放在账号密码过滤器之前的,
    也就是OaSecurityConfig中的这句话
    在这里插入图片描述

     // 验证码过滤器,加在了用户密码过滤器之前
            http.addFilterBefore(captchaFilter(), UsernamePasswordAuthenticationFilter.class);
    
    • 1
    • 2

    所以还需要编写验证码过滤器
    CaptchaFilter

    package com.manager.oa.filter;
    
    import com.google.code.kaptcha.Constants;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * 验证码过滤器
     *
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-19
     */
    public class CaptchaFilter extends OncePerRequestFilter {
        @Autowired
        private AuthenticationFailureHandler authenticationFailureHandler;
    
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            if ("/portal/tologin".equals(request.getRequestURI()) && "post".equalsIgnoreCase(request.getMethod())) {
                String code = request.getParameter("code");
                String captcha = request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY).toString();
                if (!code.equalsIgnoreCase(captcha)) {
                    // 认证失败
                    authenticationFailureHandler.onAuthenticationFailure(request, response, new ValidateException("验证码错误"));
                    return;
                }
            }
            filterChain.doFilter(request, response);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    验证码错误自定义异常

    /**
     * 验证码错误异常
     *
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-20
     */
    public class ValidateException extends AuthenticationException {
        public ValidateException(String msg, Throwable cause) {
            super(msg, cause);
        }
    
        public ValidateException(String msg) {
            super(msg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这里的验证码用的是kaptcha
    产生验证码的配置类:

    package com.manager.oa.config;
    
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import com.google.code.kaptcha.util.Config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Properties;
    
    import static com.google.code.kaptcha.Constants.*;
    
    /**
     * 图片验证码属性配置类
     *
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-19
     */
    @Configuration
    public class CaptchaConfig {
        @Bean
        public DefaultKaptcha defaultKaptcha() {
            Properties properties = new Properties();
            // 是否有边框 默认为true 我们可以自己设置yes,no
            properties.setProperty("kaptcha.border", "yes");
            // 验证码文本字符颜色 默认为Color.BLACK
            properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
            // 验证码图片宽度 默认为200
            properties.setProperty(KAPTCHA_IMAGE_WIDTH, "100");
            // 验证码图片高度 默认为50
            properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "34");
            // 验证码文本字符大小 默认为40
            properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "30");
            // KAPTCHA_SESSION_KEY
            properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "captcha");
            // 验证码文本字符长度 默认为5
            properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
            // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
            properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial");
            // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
            properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");
            Config config = new Config(properties);
    
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    在这里插入图片描述

    编写验证码的CaptchaController

    package com.manager.oa.controller.portal;
    
    import com.google.code.kaptcha.Constants;
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    
    /**
     * 图片验证码
     *
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-19
     */
    @Controller
    public class CaptchaController {
        @Autowired
        private DefaultKaptcha defaultKaptcha;
    
        @GetMapping(value = "/captcha")
        public void getKaptchaImage(HttpServletRequest request, HttpServletResponse response) {
            ServletOutputStream out = null;
            try {
                response.setDateHeader("Expires", 0);
                response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
                response.addHeader("Cache-Control", "post-check=0, pre-check=0");
                response.setHeader("Pragma", "no-cache");
                response.setContentType("image/jpeg");
                //生成验证码
                String capText = defaultKaptcha.createText();
                HttpSession session = request.getSession();
                session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
                //向客户端写出
                BufferedImage bi = defaultKaptcha.createImage(capText);
                out = response.getOutputStream();
                ImageIO.write(bi, "jpg", out);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    最后:LoginController

    @Controller("portalLoginController")
    @RequestMapping("/portal")
    public class LoginController {
    
        @RequestMapping("/login")
        public String login() {
            return "login";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    最后,我的登录界面

    DOCTYPE html>
    <html lang="zh-cn" xmlns:th="http://www.thymeleaf.org" xmlns:ch="http://www.thymeleaf.org">
    <head>
    <title>登录title>
    <link rel="stylesheet" th:href="@{/css/pintuer.css}">
    <link rel="stylesheet" th:href="@{/css/admin.css}">
    <script type="text/javascript">
    	
    script>
    head>
    <body>
    	<div class="bg">div>
    	<div class="container">
    		<div class="line bouncein">
    			<div class="xs6 xm4 xs3-move xm4-move">
    				<div style="height:150px;">div>
    				<div class="media media-y margin-big-bottom">div>
    				<form action="/portal/tologin" method="post">
    
    					<div class="panel loginbox">
    						<div class="text-center margin-big padding-big-top">
    							<h1>后台管理中心h1>
    							<ch:block ch:text="${msg}">ch:block>
    						div>
    						<div class="panel-body"
    							style="padding:30px; padding-bottom:10px; padding-top:10px;">
    							<div class="form-group">
    								<div class="field field-icon-right">
    
    									<input type="text" class="input input-big" name="account"
    										placeholder="登录账号" value="admin3"/> <span
    										class="icon icon-user margin-small">span>
    								div>
    							div>
    							<div class="form-group">
    								<div class="field field-icon-right">
    									<input type="password" class="input input-big" name="password"
    										placeholder="登录密码" value="123123" /> <span
    										class="icon icon-key margin-small">span>
    								div>
    							div>
    							<div class="form-group">
    								<div class="field">
    									<input type="text" class="input input-big" name="code"
    										   placeholder="填写右侧的验证码" style="width: 225px;display: inline"/>
    									<img src="/captcha"
    										 alt="" width="100" height="44" onclick="this.src = '/captcha?t=' + new Date().getTime();">
    								div>
    							div>
    						<div style="padding:30px;">
    							<input type="submit"
    								class="button button-block bg-main text-big input-big"
    								value="登录">
    						div>
    					div>
    				form>
    			div>
    		div>
    	div>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    最后需要用到的测试类,及html
    权限验证

     @PreAuthorize("hasAuthority('dept:list')") // 需要的权限
    
    • 1

    这个就是最开始从数据库中查询到的权限

    @Controller("portalDeptController")
    @RequestMapping("/dept")
    public class DeptController {
        @PreAuthorize("hasAuthority('dept:list')") // 需要的权限
        @GetMapping("/list")
        public String list(){
            return "dept_list";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    NoPermController 权限不足,会话过期controller

    package com.manager.oa.controller.portal;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @Author sms
     * @Version V1.0.0
     * @Date 2022-08-22
     */
    @Controller("/portal")
    public class NoPermController {
        /**
         * 没有权限
         *
         * @return
         */
        @RequestMapping("/noperm")
        public String noPerm() {
            return "noperm";
        }
    
        /**
         * 会话过期
         *
         * @return
         */
        @RequestMapping("/nosession")
        public String noSession() {
            return "nosession";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    noperm.html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    权限不足
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    nosession.html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    <a href="/portal/login" target="_top">登录a>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

  • 相关阅读:
    继NOIP2022结束以后(文化课复建)
    k8s学习-网络策略NetworkPolicy(概念、模版、创建、删除等)
    CSharp(C#)语言_委托和事件区别详解
    windows实用功能快捷入口
    【SQLite】一、SQLite简介——MySQL的简洁版
    Grafana----基于Kubernetes平台部署Grafana Loki Promtail系统
    【概率论基础进阶】随机事件和概率-随机事件、事件间的关系与运算
    如何使用php提取文章中的关键词
    Java并发 - (并发基础)
    mysql InnoDB 事务的实现原理
  • 原文地址:https://blog.csdn.net/weixin_44798538/article/details/126461932