Spring Boot 整合 Spring Security

1.建庫css

  a.建立 用戶表、角色表、關係表html

CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `sys_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `sys_user_role` (
  `user_id` int(11) NOT NULL,
  `role_id` int(11) NOT NULL
);

 

  b.初始化數據前端

INSERT INTO `sys_role` VALUES ('1', 'ROLE_ADMIN');
INSERT INTO `sys_role` VALUES ('2', 'ROLE_USER');

INSERT INTO `sys_user` VALUES ('1', 'admin', '123');
INSERT INTO `sys_user` VALUES ('2', 'test', '123');

INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '2');

COMMIT;

 

 

2.建立springboot工程java

  a.選擇Spring Web、JDBC API、MyBatis Framework、MySQL Driver、Spring Security、Thymeleaf,並手動添加 thymeleaf-extras-springsecurity5 依賴mysql

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--對Thymeleaf添加Spring Security標籤支持-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
    </dependencies>

 

 

  b.編寫 application.yml 配置web

spring:
  # 服務名稱
  application:
    name: springboot-security
  # mysql數據源
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    username: root
    password: 123456
  # thymeleaf熱加載
  thymeleaf:
    cache=false: false

# 服務端口號
server:
  port: 8081

#開啓Mybatis下劃線命名轉駝峯命名
mybatis:
  configuration:
    map-underscore-to-camel-case: true

 

 

  c.建立Entity實體類spring

    1)用戶Entitysql

public class SysUser implements Serializable {

    //ID
    private Integer id;
    //用戶名
    private String name;
    //密碼
    private String password;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

 

    2)角色Entity數據庫

public class SysRole implements Serializable {

    //ID
    private Integer id;
    //角色名稱
    private String name;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

 

    3)用戶-角色關係Entity跨域

public class SysUserRole implements Serializable {

    //用戶ID
    private Integer userId;
    //角色ID
    private Integer roleId;

    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public Integer getRoleId() {
        return roleId;
    }
    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }
}

 

 

  d.建立 Mybatis 的 Mapper

    1)用戶Mapper

@Mapper
public interface SysUserMapper {

    @Select("SELECT * FROM sys_user WHERE id = #{id}")
    SysUser selectById(Integer id);

    @Select("SELECT * FROM sys_user WHERE name = #{name}")
    SysUser selectByName(String name);
}

 

    2)角色Mapper

@Mapper
public interface SysRoleMapper {

    @Select("SELECT * FROM sys_role WHERE id = #{id}")
    SysRole selectById(Integer id);

}

 

    3)用戶-角色關係Mapper

@Mapper
public interface SysUserRoleMapper {

    @Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}")
    List<SysUserRole> listByUserId(Integer userId);

}

 

 

  e.建立Service

    1)用戶Service

@Service
public class SysUserService {

    @Resource
    private SysUserMapper userMapper;

    public SysUser selectById(Integer id) {
        return userMapper.selectById(id);
    }

    public SysUser selectByName(String name) {
        return userMapper.selectByName(name);
    }

}

 

    2)角色Service

@Service
public class SysRoleService {

    @Resource
    private SysRoleMapper roleMapper;

    public SysRole selectById(Integer id){
        return roleMapper.selectById(id);
    }

}

 

    3)用戶-角色Service

@Service
public class SysUserRoleService {

    @Resource
    private SysUserRoleMapper userRoleMapper;

    public List<SysUserRole> listByUserId(Integer userId) {
        return userRoleMapper.listByUserId(userId);
    }

}

 

 

  f.建立Controller

@Controller
public class LoginController {

    private Logger logger = LoggerFactory.getLogger(LoginController.class);

    @RequestMapping("/")
    public String showHome() {
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        logger.info("當前登錄用戶:" + name);

        return "home.html";
    }

    @RequestMapping("/login")
    public String showLogin() {
        return "login.html";
    }

    @RequestMapping("/admin")
    @ResponseBody
    @PreAuthorize("hasRole('ADMIN')")
    public String printAdmin() {
        return "若是你看見這句話,說明你有ROLE_ADMIN角色";
    }

    @RequestMapping("/user")
    @ResponseBody
    @PreAuthorize("hasRole('USER')")
    public String printUser() {
        return "若是你看見這句話,說明你有ROLE_USER角色";
    }

}

 

 

  g.配置SpringSecurity

    1)建立 Service 實現 UserDetailsService,將用戶信息和權限注入進來

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Resource
    private SysUserService userService;

    @Resource
    private SysRoleService roleService;

    @Resource
    private SysUserRoleService userRoleService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        // 從數據庫中取出用戶信息
        SysUser user = userService.selectByName(username);

        // 判斷用戶是否存在
        if(user == null) {
            throw new UsernameNotFoundException("用戶名不存在");
        }

        // 添加權限
        List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());
        for (SysUserRole userRole : userRoles) {
            SysRole role = roleService.selectById(userRole.getRoleId());
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        // 返回UserDetails實現類
        return new User(user.getName(), user.getPassword(), authorities);
    }

}

 

     2)建立 配置類 繼承 WebSecurityConfigurerAdapter

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private CustomUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
//                return DigestUtils.md5DigestAsHex((charSequence.toString() + "salt").getBytes());
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
//                return s.equals(DigestUtils.md5DigestAsHex((charSequence.toString() + "salt").getBytes()));
                return s.equals(charSequence.toString());
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/login").permitAll()//容許匿名訪問的url
//                .antMatchers("/user/**").hasRole("USER")//容許指定角色訪問的url
//                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()//其餘全部url都須要驗證
                .and()
                .exceptionHandling().accessDeniedPage("/403.html")// 權限不足自動跳轉403
                .and()

                // 設置登錄頁
                .formLogin().loginPage("/login")
                .failureUrl("/login?error")// 登錄失敗頁面(參數可供前端顯示彈框)
//                .usernameParameter("username")// 自定義登錄用戶名,默認爲username
//                .passwordParameter("password")//自定義登錄密碼參數,默認爲password
                .and()

                //登出
                .logout()
                .logoutSuccessUrl("/");

        // 關閉CSRF跨域
        http.csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) {
        // 設置攔截忽略文件夾,能夠對靜態資源放行
        web.ignoring().antMatchers("/css/**", "/js/**");
    }

}

    注:@Configuration 表示此類是個配置類,@EnableWebSecurity 表示開啓SpringSecurity服務,@EnableGlobalMethodSecurity 表示開啓SpringSecurity全局註解

 

 

  h.建立 Html 文件

    1)templates 文件夾中建立 login.html 和 home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸</title>
</head>
<body>
    <h1>登錄</h1>
    <form method="post" action="/login">
        <div>
            <label>用戶名:</label><input type="text" name="username">
        </div>
        <div>
            <label>密碼:</label><input type="password" name="password">
        </div>
        <div>
            <button type="submit">當即登錄</button>
        </div>
    </form>
</body>
</html>

 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
</head>
<body>
    <!--匿名-->
    <div sec:authorize="isAnonymous()">
        未登陸,點擊 <a th:href="@{/login}">登陸</a>
    </div>

    <!--登陸-->
    <div sec:authorize="isAuthenticated()">
        <h1>登錄成功</h1>
        <p>用戶名: <span sec:authentication="principal.username"></span></p>
        <p>權限: <span sec:authentication="principal.authorities"></span></p>
        <p>
            <span sec:authorize="hasRole('ADMIN')">這段話ADMIN能看到</span>
            <span sec:authorize="hasRole('USER')">這段話USER能看到</span>
        </p>
        <a href="/admin">檢測ADMIN角色</a>
        <a href="/user">檢測USER角色</a>
        <button onclick="location.href='/logout'">退出登陸</button>
    </div>
</body>
</html>

 

     2)在 static 文件夾中建立 403.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>權限不足</title>
</head>
<body>
    <h1>權限不足</h1>
</body>
</html>

 

 

3.啓動服務登陸 http://localhost:8081 測試效果

 

4.注意

  a.數據庫中角色名稱務必加上 「ROLE_」 前綴,authorities.add(new SimpleGrantedAuthority(role.getName())) 須要 「ROLE_」打頭的的名稱

  b.hasRole('ADMIN') 須要去掉 「ROLE_」 前綴,而 hasAuthority("ROLE_ADMIN") 則須要加上「ROLE_」 前綴,即 hasRole('ADMIN')  與 hasAuthority("ROLE_ADMIN")  效果相同

 

5.參考文檔

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

  https://www.jianshu.com/p/dcf227d53ab5

相關文章
相關標籤/搜索