springboot-27-security(一)
阿新 • • 發佈:2017-08-17
mapper logout names turn 其中 權限 xmlns int 啟動程序
spring security 使用眾多的攔截器實現權限控制的, 其核心有2個重要的概念: 認證(Authentication) 和授權 (Authorization)), 認證就是確認用戶可以訪問當前系統, 授權即確定用戶有相應的權限,
現在先大概過一遍整個流程,用戶登陸,會被AuthenticationProcessingFilter攔截,調用AuthenticationManager的實現,而且AuthenticationManager會調用ProviderManager來獲取用戶驗證信息(不同的Provider調用的服務不同,因為這些信息可以是在數據庫上,可以是在LDAP服務器上,可以是xml配置文件上等),如果驗證通過後會將用戶的權限信息封裝一個User放到spring的全局緩存SecurityContextHolder中,以備後面訪問資源時使用。 訪問資源(即授權管理),訪問url時,會通過AbstractSecurityInterceptor攔截器攔截,其中會調用FilterInvocationSecurityMetadataSource的方法來獲取被攔截url所需的全部權限,在調用授權管理器AccessDecisionManager,這個授權管理器會通過spring的全局緩存SecurityContextHolder獲取用戶的權限信息,還會獲取被攔截的url和被攔截url所需的全部權限,然後根據所配的策略(有:一票決定,一票否定,少數服從多數等),如果權限足夠,則返回,權限不夠則報錯並調用權限不足頁面 ( http://blog.csdn.net/u012367513/article/details/38866465) 本例的用戶和角色信息存儲在mysql, 使用mybatis進行查詢: http://www.cnblogs.com/wenbronk/p/7351975.html1, 導入基礎數據, 調試mybatis
1) , 建表
/* Navicat MySQL Data Transfer Source Server : 本地 Source Host : localhost:3306 Source Database : test Target Server Type : MYSQL Date: 2017-8-14 22:17:33 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `sys_user` -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` INT (32) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵id‘, `username` varchar(32) DEFAULT NULL COMMENT ‘用戶名‘, `password` varchar(32) DEFAULT NULL COMMENT ‘密碼‘, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `sys_role` -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` INT (32) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵id‘, `name` varchar(32) DEFAULT NULL COMMENT ‘用戶名‘, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `sys_role_user` -- ---------------------------- DROP TABLE IF EXISTS `sys_role_user`; CREATE TABLE `sys_role_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵id‘, `sys_user_id` INT(32) NOT NULL COMMENT ‘user_id‘, `sys_role_id` INT(32) NOT NULL COMMENT ‘role_id‘, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8; ALTER TABLE sys_role_user ADD CONSTRAINT sys_FK1 FOREIGN KEY(sys_user_id) REFERENCES sys_user(id); ALTER TABLE sys_role_user ADD CONSTRAINT role_FK2 FOREIGN KEY(sys_role_id) REFERENCES sys_role(id);
導入數據
insert into SYS_USER (id,username, password) values (1,‘vini‘, ‘123‘); insert into SYS_USER (id,username, password) values (2,‘bronk‘, ‘123‘); insert into SYS_ROLE(id,name) values(1,‘ROLE_ADMIN‘); insert into SYS_ROLE(id,name) values(2,‘ROLE_USER‘); insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(1,1); insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(2,2);
在 application.yml中配置如下, 可以在啟動程序時自動執行
spring: datasource: url: jdbc:mysql://localhost:3306/springboot username: root password: root # type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver
# 一下2行 schema: classpath:security.sql data: classpath:security-data.sql
2), mapper映射
package com.wenbronk.security.mapper import com.wenbronk.security.entity.SysUser /** * Created by wenbronk on 2017/8/14. */ interface SysUserMapper { SysUser findByUserName(String username) }
在 resources/mybatis/mapper中添加:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.wenbronk.security.mapper.SysUserMapper"> <resultMap id="sys_user_map" type="SysUser"> <id property="id" column="id" /> <result property="username" column="username" /> <result property="password" column="password" /> <collection property="roles" ofType="SysRole"> <result column="name" property="name" /> </collection> </resultMap> <select id="findByUserName" parameterType="string" resultMap="sys_user_map"> select u.id, u.username, u.password, r.name from sys_user u LEFT JOIN sys_role_user s on u.id = s.sys_user_id LEFT JOIN sys_role r on r.id = s.sys_role_id WHERE username = #{username} </select> </mapper>
在application.yml中配置
mybatis: config-location: classpath:mybatis/SqlMapConfig.xml mapper-locations: classpath:mybatis/mapper/*.xml
在main方法上添加mapper掃描:
@SpringBootApplication @MapperScan("com.wenbronk.security.mapper") public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class); } }
3) , 測試mybatis
@Test void test2() { def name = sysUserMapper.findByUserName(‘vini‘) println name }
2, security相關配置
1), CustomerUserService.groovypackage com.wenbronk.security.security.service import com.wenbronk.security.entity.SysRole import com.wenbronk.security.entity.SysUser import com.wenbronk.security.mapper.SysUserMapper 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.Service import javax.inject.Inject /** * Created by wenbronk on 2017/8/15. */ @Service class CustomUserService implements UserDetailsService { @Inject SysUserMapper sysUserMapper; @Override UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { def sysUser = sysUserMapper.findByUserName(s) as SysUser assert sysUser != null List<SimpleGrantedAuthority> authorities = new ArrayList<>() for(SysRole role : sysUser.getRoles()) { authorities.add(new SimpleGrantedAuthority(role.getName())) println role.getName(); } return new User(sysUser.getUsername(), sysUser.getPassword(), authorities) } }
2), WebSecurityConfig.groovy
package com.wenbronk.security.security.config import com.wenbronk.security.security.service.CustomUserService import org.springframework.context.annotation.Configuration import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter import javax.inject.Inject /** * Created by wenbronk on 2017/8/15. */ @Configuration @EnableWebSecurity class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Inject CustomUserService customUserService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customUserService); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() // 任何請求都攔截 .and() .formLogin() .loginPage("/login") .failureUrl("/login?error") .permitAll() // 登陸後可訪問任意頁面 .and() .logout().permitAll(); // 註銷後任意訪問 } }
3, 頁面
1), 頁面轉向設置
package com.wenbronk.security.config import org.springframework.context.annotation.Configuration import org.springframework.web.servlet.config.annotation.ViewControllerRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter /** * Created by wenbronk on 2017/8/15. */ @Configuration class WebMvcConfig extends WebMvcConfigurerAdapter{ @Override void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login") } }
controller.groovy
package com.wenbronk.security.controller import com.wenbronk.security.entity.Msg import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.RequestMapping /** * Created by wenbronk on 2017/8/14. */ @Controller class SecurityController { @RequestMapping("/") def index(Model model) { def msg = new Msg("測試標題", "測試內容", "額外信息, 只對管理員顯示") model.addAttribute("msg", msg); "home" } }
在resources下放入靜態資源, bootstramp.min.css, 以及thymeleaf頁面
login.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta content="text/html;charset=UTF-8"/> <title>登錄頁面</title> <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/> <style type="text/css"> body { padding-top: 50px; } .starter-template { padding: 40px 15px; text-align: center; } </style> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="#">Spring Security演示</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li><a th:href="@{/}"> 首頁 </a></li> </ul> </div><!--/.nav-collapse --> </div> </nav> <div class="container"> <div class="starter-template"> <p th:if="${param.logout}" class="bg-warning">已成功註銷</p><!-- 1 --> <p th:if="${param.error}" class="bg-danger">有錯誤,請重試</p> <!-- 2 --> <h2>使用賬號密碼登錄</h2> <form name="form" th:action="@{/login}" action="/login" method="POST"> <!-- 3 --> <div class="form-group"> <label for="username">賬號</label> <input type="text" class="form-control" name="username" value="" placeholder="賬號" /> </div> <div class="form-group"> <label for="password">密碼</label> <input type="password" class="form-control" name="password" placeholder="密碼" /> </div> <input type="submit" id="login" value="Login" class="btn btn-primary" /> </form> </div> </div> </body> </html>
home.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head> <meta content="text/html;charset=UTF-8"/> <title sec:authentication="name"></title> <link rel="stylesheet" th:href="@{css/bootstrap.min.css}" /> <style type="text/css"> body { padding-top: 50px; } .starter-template { padding: 40px 15px; text-align: center; } </style> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="#">Spring Security演示</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li><a th:href="@{/}"> 首頁 </a></li> </ul> </div><!--/.nav-collapse --> </div> </nav> <div class="container"> <div class="starter-template"> <h1 th:text="${msg.title}"></h1> <p class="bg-primary" th:text="${msg.content}"></p> <div sec:authorize="hasRole(‘ROLE_ADMIN‘)"> <!-- 用戶類型為ROLE_ADMIN 顯示 --> <p class="bg-info" th:text="${msg.etraInfo}"></p> </div> <div sec:authorize="hasRole(‘ROLE_USER‘)"> <!-- 用戶類型為 ROLE_USER 顯示 --> <p class="bg-info">無更多信息顯示</p> </div> <form th:action="@{/logout}" method="post"> <input type="submit" class="btn btn-primary" value="註銷"/> </form> </div> </div> </body> </html>
參見: JavaEE顛覆者, springboot實戰
springboot-27-security(一)