springboot+spring security+mybaits實現登入許可權管理
序:
本文采用springboot+spring security+mybatis來解決登入許可權管理的問題。由於是新人,所以在操作方面講得比較詳細。
話不多說,直接來開始我們的專案。
1 建立springboot+spring security+mybatis 專案
這裡我們採用了intellIJidea編輯器。
1.1 建立springboot專案(jdk採用1.8版本)
1.2 對專案進行配置
1.3 勾選我們需要的架包依賴
1.4 對專案進行最終的命名及專案位置確定
2 對application.properties以及pom.xml檔案進行配置
2.1 application.properties(我們可以隨時修改其中資料庫的地址及其他相關資料)
jdbc.db.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.db.url=jdbc:mysql://localhost:3306/mydemo?serverTimezone=UTC&characterEncoding=utf-8&useSSL=false
jdbc.db.username=root
jdbc.db.password=admin
jdbc.db.maxActive=500
logging.level.org.springframework.security= INFO
spring.thymeleaf.cache=false
2.2 pom.xml(若你按照我的方式建立專案有可能執行不起來,可能是架包版本的緣故,可複製我的)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>security-mybatis</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.0.RELEASE</version> </parent> <properties> <start-class>com.us.Application</start-class> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <mybatis.version>3.2.7</mybatis.version> <mybatis-spring.version>1.2.2</mybatis-spring.version> </properties> <dependencies> <!--springboot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency> <!--db--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.5</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <!--mybatis--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis-spring.version}</version> </dependency> </dependencies> </project>
3 資料庫設計
3.1 資料庫表的設計,登入比較簡單,只有五張表,分別是使用者表(sys_user),角色表(sys_role),許可權表(sys_permission),角色許可權關係表(sys_role_user),角色使用者關係表(sys_role_permission).
然後我們往裡面填充一點資料
insert into SYS_USER (id,username, password) values (1,'admin', 'admin');
insert into SYS_USER (id,username, password) values (2,'user', 'user');
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,ROLES_ID) values(1,1);
insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(2,2);
BEGIN;
INSERT INTO `Sys_permission` VALUES ('1', 'ROLE_HOME', 'home', '/', null), ('2', 'ROLE_ADMIN', 'user', '/admin', null);
COMMIT;
BEGIN;
INSERT INTO `Sys_permission_role` VALUES ('1', '1', '1'), ('2', '1', '2'), ('3', '2', '1');
COMMIT;
3.2 實體類的建立
3.2.1 SysUser.java
package com.example.securitymybatis.entity;
import java.util.List;
//使用者表(sys_user表)
public class SysUser {
//主鍵id
private Integer id;
//使用者名稱
private String username;
//登入密碼
private String password;
private List<SysRole> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
}
3.2.2 SysRole.java
package com.example.securitymybatis.entity;
//角色表(sys_role表)
public class SysRole {
//主鍵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.2.3 Permission.java
package com.example.securitymybatis.entity; //許可權表(sys_permission表) public class Permission { //主鍵id private int id; //許可權名稱 private String name; //許可權描述 private String descritpion; //授權連結 private String url; //父節點id private int pid; //請求方式 private String method; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescritpion() { return descritpion; } public void setDescritpion(String descritpion) { this.descritpion = descritpion; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } }
3.2.4 Message.java
package com.example.securitymybatis.entity;
//中間資訊表(無資料庫實體表,只用來專遞中間資訊)
public class Message {
//資訊標題
private String title;
//資訊主體
private String content;
//額外資訊
private String etraInfo;
public Message(String title, String content, String etraInfo) {
super();
this.title = title;
this.content = content;
this.etraInfo = etraInfo;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getEtraInfo() {
return etraInfo;
}
public void setEtraInfo(String etraInfo) {
this.etraInfo = etraInfo;
}
}
4 config配置
4.1 DBconfig.java配置
package com.example.securitymybatis.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import java.beans.PropertyVetoException;
//配置資料來源
@Configuration
public class DBconfig {
@Autowired
private Environment env;
@Bean(name="dataSource")
public ComboPooledDataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(env.getProperty("jdbc.db.driverClassName"));
dataSource.setJdbcUrl(env.getProperty("jdbc.db.url"));
dataSource.setUser(env.getProperty("jdbc.db.username"));
dataSource.setPassword(env.getProperty("jdbc.db.password"));
dataSource.setMaxPoolSize(20);
dataSource.setMinPoolSize(5);
dataSource.setInitialPoolSize(10);
dataSource.setMaxIdleTime(300);
dataSource.setAcquireIncrement(5);
dataSource.setIdleConnectionTestPeriod(60);
return dataSource;
}
}
4.2 MybaitsConfig.java配置
package com.example.securitymybatis.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
//掃描mapper檔案
@Configuration
@ComponentScan
public class MybatisConfig {
@Autowired
private DataSource dataSource;
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean sqlSessionFactory(ApplicationContext applicationContext) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});
sessionFactory.setMapperLocations(applicationContext.getResources("classpath*:mapper/*.xml"));
return sessionFactory;
}
}
4.3 MybatisScannerConfig.java配置
package com.example.securitymybatis.config;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//掃描dao層檔案
@Configuration
public class MybatisScannerConfig {
@Bean
public MapperScannerConfigurer MapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.example.securitymybatis.dao");
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return mapperScannerConfigurer;
}
}
4.4 TransactionConfig.java配置
package com.example.securitymybatis.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.sql.DataSource;
//開啟事務管理
@Configuration
@ComponentScan
public class TransactionConfig implements TransactionManagementConfigurer {
@Autowired
private DataSource dataSource;
@Bean(name = "transactionManager")
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
4.5 WebMvcConfig.java 配置
package com.example.securitymybatis.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
//web檢視管理
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
package com.example.securitymybatis.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
//web檢視管理
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
4.6 WebSecurityConfig.java 配置(本文核心配置,請看註釋)
package com.example.securitymybatis.config;
import com.example.securitymybatis.security.MyFilterSecurityInterceptor;
import com.example.securitymybatis.security.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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 org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
//業務核心
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
@Bean
UserDetailsService customUserService(){ //註冊UserDetailsService 的bean
return new UserService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService()); //user Details Service驗證
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// // http.authorizeRequests()每個匹配器按照它們被宣告的順序被考慮。
http
.authorizeRequests()
// 所有使用者均可訪問的資源
.antMatchers("/css/**", "/js/**", "/images/**", "/webjars/**", "**/favicon.ico").permitAll()
// ROLE_USER的許可權才能訪問的資源
.antMatchers("/user/**").hasRole("USER")
// 任何尚未匹配的URL只需要驗證使用者即可訪問
.anyRequest().authenticated()
.and()
.formLogin()
// 指定登入頁面,授予所有使用者訪問登入頁面
.loginPage("/login")
//設定預設登入成功跳轉頁面,錯誤回到login介面
.defaultSuccessUrl("/index").failureUrl("/login?error").permitAll()
.and()
//開啟cookie儲存使用者資料
.rememberMe()
//設定cookie有效期
.tokenValiditySeconds(60 * 60 * 24 * 7)
//設定cookie的私鑰
.key("security")
.and()
.logout()
.permitAll();
//登入攔截器
http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)
//springsecurity4自動開啟csrf(跨站請求偽造)與restful衝突
.csrf().disable();
}
}
完成config後我們開始從自底向上的方式來編寫我們的登陸功能。
5 mapper的配置
5.1 UserDaoMapper.xml 配置
<?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.example.securitymybatis.dao.UserDao">
<resultMap id="userMap" type="com.example.securitymybatis.entity.SysUser">
<id property="id" column="ID"/>
<result property="username" column="username"/>
<result property="password" column="PASSWORD"/>
<collection property="roles" ofType="com.example.securitymybatis.entity.SysRole">
<result column="name" property="name"/>
</collection>
</resultMap>
<select id="findByUserName" parameterType="String" resultMap="userMap">
select u.*
,r.name
from sys_user u
LEFT JOIN sys_role_user sru on u.id= sru.sys_user_id
LEFT JOIN sys_role r on sru.sys_role_id=r.id
where username= #{username}
</select>
</mapper>
5.2 PermissionDaoMapper.xml 配置
<?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.example.securitymybatis.dao.PermissionDao">
<select id="findAll" resultType="com.example.securitymybatis.entity.Permission">
SELECT * from Sys_permission ;
</select>
<select id="findByAdminUserId" parameterType="int" resultType="com.example.securitymybatis.entity.Permission">
select p.*
from sys_user u
LEFT JOIN sys_role_user sru on u.id= sru.sys_user_id
LEFT JOIN sys_role r on sru.sys_role_id=r.id
LEFT JOIN sys_permission_role spr on spr.role_id=r.id
LEFT JOIN sys_permission p on p.id =spr.permission_id
where u.id=#{userId}
</select>
</mapper>
6 dao層介面配置
6.1 UserDao.java
package com.example.securitymybatis.dao;
import com.example.securitymybatis.entity.SysUser;
public interface UserDao {
public SysUser findByUserName(String username);
}
6.2 PermissionDao.java
package com.example.securitymybatis.dao;
import com.example.securitymybatis.entity.Permission;
import java.util.List;
public interface PermissionDao {
public List<Permission> findAll();
public List<Permission> findByAdminUserId(int userId);
}
7 serivice 層配置
7.1 UserService.java(其中會用到後面寫到的方法)
package com.example.securitymybatis.security;
import com.example.securitymybatis.dao.PermissionDao;
import com.example.securitymybatis.dao.UserDao;
import com.example.securitymybatis.entity.Permission;
import com.example.securitymybatis.entity.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 org.springframework.security.core.userdetails.User;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserService implements UserDetailsService { //自定義UserDetailsService 介面
@Autowired
UserDao userDao;
@Autowired
PermissionDao permissionDao;
@Override
public UserDetails loadUserByUsername(String username) { //重寫loadUserByUsername 方法獲得 userdetails 型別使用者
SysUser user = userDao.findByUserName(username);
if (user != null) {
List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());
List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
for (Permission permission : permissions) {
if (permission != null && permission.getName()!=null) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
//1:此處將許可權資訊新增到 GrantedAuthority 物件中,在後面進行全許可權驗證時會使用GrantedAuthority 物件。
grantedAuthorities.add(grantedAuthority);
}
}
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
} else {
throw new UsernameNotFoundException("admin: " + username + " do not exist!");
}
}
}
8 controller層配置
8.1 LoginController.java(其中有幾個方法的許可權是管理員才有的)
package com.example.securitymybatis.controller;
import com.example.securitymybatis.entity.Message;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LoginController {
@RequestMapping("/index")
public String index(Model model){
Message msg = new Message("測試標題","測試內容","額外資訊,只對管理員顯示");
model.addAttribute("msg", msg);
return "index";
}
@RequestMapping("/admin")
@ResponseBody
public String hello(){
return "hello admin";
}
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping(value = "/user", method = RequestMethod.GET)
@ResponseBody
public String getList(){
return "hello getList";
}
@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
public String save(){
return "hello save";
}
@RequestMapping(value = "/user", method = RequestMethod.PUT)
@ResponseBody
public String update(){
return "hello update";
}
}
9 security 配置(核心)
9.1 MyAccessDecisionManager.java(授權管理器)
package com.example.securitymybatis.security;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Iterator;
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {
// decide 方法是判定是否擁有許可權的決策方法,
//authentication 是釋CustomUserService中迴圈新增到 GrantedAuthority 物件中的許可權資訊集合.
//object 包含客戶端發起的請求的requset資訊,可轉換為 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//configAttributes 為MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法返回的結果,此方法是為了判定使用者請求的url 是否在許可權表中,如果在許可權表中,則返回給 decide 方法,用來判定使用者是否有此許可權。如果不在許可權表中則放行。
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if(null== configAttributes || configAttributes.size() <=0) {
return;
}
ConfigAttribute c;
String needRole;
for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
c = iter.next();
needRole = c.getAttribute();
for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 為在註釋1 中迴圈新增到 GrantedAuthority 物件中的許可權資訊集合
if(needRole.trim().equals(ga.getAuthority())) {
return;
}
}
}
throw new AccessDeniedException("no right");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
9.2 MyFilterSecurityInterceptor.java (自定義攔截器)package com.example.securitymybatis.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;
import javax.servlet.*;
import java.io.IOException;
@Service
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
@Autowired
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Autowired
public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
super.setAccessDecisionManager(myAccessDecisionManager);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
//fi裡面有一個被攔截的url
//裡面呼叫MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法獲取fi對應的所有許可權
//再呼叫MyAccessDecisionManager的decide方法來校驗使用者的許可權是否足夠
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
//執行下一個攔截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
@Override
public void destroy() {
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
}
9.3 MyInvocationSecurityMetadataSourceService.java(獲取被攔截url所需的全部許可權的方法)
package com.example.securitymybatis.security;
import com.example.securitymybatis.dao.PermissionDao;
import com.example.securitymybatis.entity.Permission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
@Service
public class MyInvocationSecurityMetadataSourceService implements
FilterInvocationSecurityMetadataSource {
@Autowired
private PermissionDao permissionDao;
private HashMap<String, Collection<ConfigAttribute>> map =null;
/**
* 載入許可權表中所有許可權
*/
public void loadResourceDefine(){
map = new HashMap<>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg;
List<Permission> permissions = permissionDao.findAll();
for(Permission permission : permissions) {
array = new ArrayList<>();
cfg = new SecurityConfig(permission.getName());
//此處只添加了使用者的名字,其實還可以新增更多許可權的資訊,例如請求方法到ConfigAttribute的集合中去。此處新增的資訊將會作為MyAccessDecisionManager類的decide的第三個引數。
array.add(cfg);
//用許可權的getUrl() 作為map的key,用ConfigAttribute的集合作為 value,
map.put(permission.getUrl(), array);
}
}
//此方法是為了判定使用者請求的url 是否在許可權表中,如果在許可權表中,則返回給 decide 方法,用來判定使用者是否有此許可權。如果不在許可權表中則放行。
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
if(map ==null) loadResourceDefine();
//object 中包含使用者請求的request 資訊
HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
AntPathRequestMatcher matcher;
String resUrl;
for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
resUrl = iter.next();
matcher = new AntPathRequestMatcher(resUrl);
if(matcher.matches(request)) {
return map.get(resUrl);
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
如上所示security的攔截器就配好了,如果有看不懂的地方,可在網上搜security攔截器,我這裡就不一一詳細解釋了。
10 介面程式碼
10.1 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;
}
.form-group input{
margin: auto;
width: 550px;
}
</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>
10.2 index.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>
<li><a th:href="@{/admin}"> admin </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_ADMIN')"> <!-- 使用者型別為ROLE_ADMIN 顯示 -->
<p class="bg-info">恭喜您,您有 ROLE_ADMIN 許可權 </p>
</div>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="登出"/>
</form>
</div>
</div>
</body>
</html>
11 整體結構和執行效果。
整個專案的檔案結構如上圖所示,static下的css資料夾中只有一個bootstrap.min.css檔案,網上都能搜到,我就不上傳了。
11.1 執行專案,點選右上角的綠色三角形執行專案,不需要配置tomcat.
11.2 開啟瀏覽器,輸入localhost:8080即可進入登入介面
11.3 管理員和普通使用者登入顯示不同的內容
11.3.1 管理員登入顯示
11.3.2 普通使用者登入顯示
11.4 點選管理員登入後跳轉介面上的admin,頁面會顯示“hello admin”,而普通使用者會有403錯誤。
11.4.1 管理員點選admin
11.4.2 普通使用者點選admin
至此,整個springboot+springsecurity+mybaits專案就搭建好了。
相關推薦
springboot+spring security+mybaits實現登入許可權管理
序:本文采用springboot+spring security+mybatis來解決登入許可權管理的問題。由於是新人,所以在操作方面講得比較詳細。話不多說,直接來開始我們的專案。1 建立springboot+spring security+mybatis 專案這裡我們採用了
SpringBoot+Spring Security Oauth2實現客戶端授權
框架使用SpringBoot 1.5 + Spring Security Oauth2 主要完成了客戶端授權 可以通過mysql資料庫 將客戶端與token資訊儲存在資料庫中。 每次授權會將新的token儲存在mysql中,進行客戶端驗證時,先會從資料庫中查詢客
(一)如何使用Spring-security來實現登入驗證功能(XML配置方式)?
先從使用xml的方式來實現使用者的許可權登入 (1)需要在maven工程中加上關於spring-secutity的jar包的依賴 //spring-securityd 有關的依賴 <
SpringBoot+Spring Security無法實現跨域解決辦法
未使用Security時跨域: import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframewor
springBoot整合spring security+JWT實現單點登入與許可權管理前後端分離--築基中期
## 寫在前面 在前一篇文章當中,我們介紹了springBoot整合spring security單體應用版,在這篇文章當中,我將介紹springBoot整合spring secury+JWT實現單點登入與許可權管理。 本文涉及的許可權管理模型是**基於資源的動態許可權管理**。資料庫設計的表有 user
Springboot整合Security實現登入許可權驗證
緒: 通過這個查,參照別人的demo實現了security許可權認證,可能有些地方寫的不對,供參考!希望對你有幫助 一.配置 1.pom配置 <?xml version="1.0" encoding="UTF-8"?>
(二)如何使用spring-security來實現使用者的登入許可權功能?(配合使用資料庫的方式)
如何使用spring-security來實現使用者的登入功能之配合使用資料庫的方式 這個圖大家先熟悉一下簡單的過一遍,等把步驟都寫完之後,後面會總結 (一)使用spring-security之前需要做的準備(基於springMVC和dubbo的專案)
jwt,spring security ,feign,zuul,eureka 前後端分離 整合 實現 簡單 許可權管理系統 與 使用者認證的實現
本例子 包含有 一下模組: eureka 模組,充當 註冊中心角色 user-service-api 客戶端介面和實體 user-service-provider 客戶端服務提供者 user-conusmer 客戶端消費者 zuul 模組為閘道器,用來實現統一路由
Spring Boot Security + MyBatis 實現登入的安全控制機制
篇幅有限,前端的頁面程式碼就不贅述了,直接分享後端邏輯程式碼: 1.Maven專案物件依賴檔案Pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.or
spring security + thymeleaf 判斷登入使用者的許可權
spring security的UserDetailService是我自己定義的。 @Component public class MyUserDetailsService implements UserDetailsService {@Autowired private
SpringCloud+SpringBoot+OAuth2+Spring Security+Redis實現的微服務統一認證授權
因為目前做了一個基於Spring Cloud的微服務專案,所以瞭解到了OAuth2,打算整合一下OAuth2來實現統一認證。關於OAuth是一個關於授權的開放網路標準,目前的版本是2.0,這裡我就不多做介紹了。下面貼一下我學習過程中參考的資料。 理解OAuth 2.0——阮一峰 Spring
Spring security 自定義登入與許可權控制
一、先說必要的配置檔案: 1、web.xml檔案新增上 <!-- Spring Security 許可權框架 --> <filter> <filter-name>springSecurityFilterChain</filt
spring-security4.2實現登入退出以及許可權配置
最近用到了spring-security框架來實現登入驗證。 以前做登入的步驟是: 1、使用者輸入使用者名稱、密碼登入 2、連線資料庫對使用者名稱、密碼進行驗證 3、獲取使用者資訊(角色列表等等) 4、獲取相關操作許可權 security安全框架有
SpringBoot通過自己的配置檔案或者從資料庫spring security動態配置url許可權
我使用springboot的時候想做自己的配置檔案的,用不了xml就重寫了過濾器 首先需要了解spring security內建的各種filter: Alias Filter Class Namespace Element or Attribute CHANNEL
SpringBoot + Spring Security 學習筆記實現短信驗證碼+登錄功能
pass lsa nproc 驗證 過期 ant chan oci 功能 在 Spring Security 中基於表單的認證模式,默認就是密碼帳號登錄認證,那麽對於短信驗證碼+登錄的方式,Spring Security 沒有現成的接口可以使用,所以需要自己的封裝一個類似的
基於spring-security-oauth2實現單點登入(持續更新)
##基於spring-security-實現資料庫版## 文章程式碼地址:[連結描述][1]可以下載直接執行,基於springb
【手摸手,帶你搭建前後端分離商城系統】03 整合Spring Security token 實現方案,完成主業務登入
## 【手摸手,帶你搭建前後端分離商城系統】03 整合Spring Security token 實現方案,完成主業務登入 上節裡面,我們已經將基本的前端 `VUE + Element UI` 整合到了一起。並且通過 `axios` 傳送請求到後端API。 解決跨域問題後、成功從後端獲取到資料。 本小結
Spring security csrf實現前端純html+ajax
var light urn span 同時 pan mode eth res spring security集成csrf進行post等請求時,為了防止csrf攻擊,需要獲取token才能訪問 因此需要添加 <input type="hidden" name="${_
Spring Security的使用(訪問許可權控制)
訪問許可權控制 粗粒度:對一個功能的訪問進行控制 細粒度:對該功能下的資料顯示進行控制 注意:許可權控制,需要在spring-mvc.xml中配置,否則會導致失效 <aop:aspectj-autoproxy proxy-target-class="true"></a
Spring Security簡單實現自定義退出功能
1.前端頁面寫法 <a href="javascript:;" onclick="logoutBackground()">退出</a> 2.js /** * 退出後臺 */ function logoutBackground() { $.get("/