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命令運行

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM