SpringBoot整合SpringSecurity,页面使用jsp

1.创建工程并引入坐标

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- 设定一个空值将始终从仓库中获取,不从本地路径获取 查找顺序:relativePath元素中的地址–本地仓库–远程仓库 -->
    </parent>
    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringSecurity -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- jsp页面使用jstl标签 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <!-- 用于编译jsp -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- Provided 编译和测试的时候使用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- 通用mapper -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.5</version>
        </dependency>
    </dependencies>
View Code

2.加入jsp页面等静态资源:
  在src/main目录下创建webapp目录

    

   这时webapp目录并不能正常使用,因为只有web工程才有webapp目录,在pom文件中修改项目为web工程

    

3.编写控制器

@Controller
@RequestMapping("/product")
public class ProductController {

    @Secured({"ROLE_PRODUCT", "ROLE_ADMIN"}) // SpringSecurity内部制定的注解
    // @RolesAllowed({"ROLE_PRODUCT", "ROLE_ADMIN"}) // jsr250注解
    // @PreAuthorize("hasAnyRole('ROLE_PRODUCT', 'ROLE_ADMIN')") // spring的el表达式注解
    @GetMapping("/findAll")
    public String findAll() {
        return "product-list";
    }
}
View Code

4.创建角色 pojo对象

  这里直接使用SpringSecurity的角色规范,实现GrantedAuthority接口

public class SysRole implements GrantedAuthority {

    private Integer id;
    private String roleName;
    private String roleDesc;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getRoleDesc() {
        return roleDesc;
    }

    public void setRoleDesc(String roleDesc) {
        this.roleDesc = roleDesc;
    }

    @JsonIgnore // 在将来我们可能会拿这个实体类转成json字符串,或者json转成java对象,需要忽略重写的几个属性
    @Override
    public String getAuthority() {
        return roleName;
    }
}
View Code

5.创建用户pojo对象
  这里直接实现SpringSecurity的用户对象接口UserDetails,并添加角色集合私有属性。

public class SysUser implements UserDetails {

    private Integer id;
    private String username;
    private String password;
    // 在MySql中是没有直接定义成Boolean这种数据类型.
    // 它只能定义成 tinyint(1) ;
    // status等于1时代表true,status等于0时代表false;
    private Boolean status;
    private List<SysRole> roles;

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

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

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

    public void setPassword(String password) {
        this.password = password;
    }

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    @JsonIgnore // 在将来我们可能会拿这个实体类转成json字符串,或者json转成java对象,需要忽略重写的几个属性
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    /**
     * 账户是否失效
     * @return
     */
    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

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

    /**
     * 密码是否失效
     * @return
     */
    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 指定当前用户是否可用
     * @return
     */
    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return status;
    }
}
View Code

6.提供角色mapper接口

public interface RoleMapper extends Mapper<SysRole> {

    @Select("select * from sys_role r, sys_user_role ur where r.id=ur.rid and ur.uid = #{uid}")
    List<SysRole> findByUid(Integer uid);
}
View Code

7.提供用户mapper接口

public interface UserMapper extends Mapper<SysUser> {

    @Select("select * from sys_user where username = #{username}")
    @Results({
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "username", column = "username"),
            @Result(property = "password", column = "password"),
            @Result(property = "roles", column = "id",
                many = @Many(
                      select = "com.fgy.mapper.RoleMapper.findByUid",
                      fetchType = FetchType.EAGER
                )
            )
    })
    SysUser findByName(String username);
}
View Code

8.提供认证service接口

public interface UserService extends UserDetailsService {
}

9.提供认证 service实现类

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return userMapper.findByName(s);
    }
}
View Code

10.自定义异常页面

@ControllerAdvice
public class HandlerControllerException {

    @ExceptionHandler(RuntimeException.class)
    public String exceptionHandler(RuntimeException e) {

        if (e instanceof AccessDeniedException) {
            // 如果是权限不足异常,则跳转到权限不足页面!
            return "redirect:/403.jsp";
        }
        // 其余的异常都到500页面!
        return "redirect:/500.jsp";
    }
}
View Code

11.编写配置文件(.yml)

server:
  port: 8080

spring:
  mvc:
    view:
      prefix: /pages/
      suffix: .jsp
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///springsecurity
    username: root
    password: root

mybatis:
  type-aliases-package: com.fgy.domain
  # mybatis默认是属性名和数据库字段名一一对应的,即 
  # 数据库表列:user_name 
  # 实体类属性:user_name

  # 但是java中一般使用驼峰命名 
  # 数据库表列:user_name 
  # 实体类属性:userName

  # 在Springboot中,可以通过设置map-underscore-to-camel-case属性为true来开启驼峰功能
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    com.fgy: debug
View Code

12.提供 SpringSecurity 配置类,放在config包下

/**
 * springSecurity配置类
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true,
                            prePostEnabled = true,
                            securedEnabled = true) // 实际只开一种即可,这里只是演示
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    /**
     * 生成认证使用的加密对象,添加到容器中
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 认证用户的来源【内存或数据库】
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 指定用户的来源,一般不会这么做,这里只是测试
        /*auth.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}user")
                .roles("USER");*/

        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    // 配置springSecurity相关信息
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 释放静态资源,指定资源拦截规则,指定自定义认证页面,指定退出认证配置,csrf配置
        http.authorizeRequests()
                .antMatchers("/login.jsp", "/failer.jsp", "/css/**", "/img/**", "/plugins/**")
                .permitAll() //释放上面的资源,不需要认证即可访问
                .antMatchers("/**").hasAnyRole("ROLE_USER", "ROLE_ADMIN")
                .anyRequest().authenticated() // .anyRequest().authenticated() 表示其他请求资源需要认证之后才能访问
                .and() // 表示一个新的配置开始(配置认证信息)
                .formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginPage("/login.jsp")
                .loginProcessingUrl("/login")
                .successForwardUrl("/index.jsp")
                .failureForwardUrl("/failer.jsp")
                .permitAll() // 登录后,无论成功与否,都需要放行接下来的资源
                .and() // 配置退出登录信息
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login.jsp")
                .invalidateHttpSession(true) // 是否清空session
                .permitAll()
                .and() // csrf配置(csrf功能默认开启,如果不需要关闭,下面都不用配置了)
                .csrf()
                .disable(); // 关闭csrf防护
    }
}
View Code

13.编写启动类

@SpringBootApplication
@MapperScan("com.fgy.mapper")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
View Code

14.使用maven命令运行

  

原文地址:https://www.cnblogs.com/roadlandscape/p/12487086.html