SpringBoot整合SpringSecurity:https://www.bilibili.com/video/BV1KE411i7bC?p=1
SpringBoot整合Shiro框架:https://www.bilibili.com/video/BV1NE411i7S8?p=1
SpringBoot文档:http://felord.cn/_doc/_springboot/2.1.5.RELEASE/_book/
https://docs.spring.io/spring-boot/docs/current/reference/html/
系统安全框架,用于认证、授权
1、SpringSecurity依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.5.3</version> </dependency>
2、命名空间xmlns:th=http://www.thymeleaf.org xmlns:sec=http://www.thymeleaf.org/extras/spring-security xmlns:shiro=http://www.pollix.at/thymeleaf/shiro
3、自己创建SecurityConfig
package com.jay.SpringBootStudy8.config;
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.crypto.bcrypt.BCryptPasswordEncoder;
import static org.springframework.security.config.Customizer.withDefaults;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// super.configure(auth);
//BCryptPasswordEncoder 加密方式,用户名admin、密码123456,可以and()连接多个
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
.and()
.withUser("user1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2")
;
}
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.authorizeRequests(authorize -> authorize.anyRequest().authenticated()).oauth2Login(withDefaults());
//首页/所有人可访问
//功能页只有具有权限的人才能访问
http.authorizeRequests()
.antMatchers("/level1").hasRole("vip1")
.antMatchers("/level2").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//禁用csrf跨站
http.csrf().disable();
//开启登录,定制登录页,自定义请求参数名 和 登录请求地址。
//如果不自定义登录请求地址,那登录form的action需要是loginPage指定的地址 /userLogin
http.formLogin().loginPage("/userLogin")
.usernameParameter("uname")
.passwordParameter("pwd")
.loginProcessingUrl("/loginHandler");
//记住我,自定义请求参数
http.rememberMe().rememberMeParameter("remember");
//注销、删除cookie、清除session
http.logout().deleteCookies("remove").invalidateHttpSession(true);
}
}
表单userLogin:
<form method="post" th:action="@{/loginHandler}">
username:<input type="text" name="uname" />
<br/>
password:<input type="password" name="pwd" />
<br/>
<input type="checkbox" name="remember" />Remember Me
<br/>
<button type="submit">submit</button>
</form>
loginHandler可以处理自己其他的登录逻辑。
页面中获取Spring Security登录用户数据:https://www.cnblogs.com/softidea/p/6677665.html https://blog.csdn.net/cyan20115/article/details/106552758
Spring Security使用jdbc进行权限验证:https://blog.csdn.net/fuzekun/article/details/104344472
Shiro:https://www.jianshu.com/p/7f724bec3dc3
1、引入相关包
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.1.0</version> </dependency> <!--工具类--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.8</version> </dependency>
2、 自定义ShiroConfig
package com.jay.SpringBootStudy8.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
/*
anon:无需认证即可访问
authc:必须认证才可访问
user:必须拥有记住我的功能,才可以用
perms:必须拥有对某个资源的权限才可以访问
role:拥有某个角色才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//对所有用户认证,只要登录成功,就可以访问
//filterMap.put("/sys/*", "authc");
//必须拥有资源权限(推荐),users:mgr 是权限码,存于数据库
// filterMap.put("/sys/users", "perms[users:mgr]");
filterMap.put("/sys/roles", "perms[roles:mgr]");
filterMap.put("/sys/permissions", "perms[permissions:mgr]");
filterMap.put("/sys/products", "perms[products:mgr]");
filterMap.put("/sys/articles", "perms[articles:mgr]");
filterMap.put("/sys/test", "perms[sys:test]");
filterMap.put("/logout", "logout");//登出
filterMap.put("/loginHandler", "anon");
bean.setLoginUrl("/login");//登录
bean.setSuccessUrl("/sys/main");//首页
bean.setUnauthorizedUrl("/noauth");//错误页面,认证不通过跳转
bean.setFilterChainDefinitionMap(filterMap);
return bean;
}
//权限管理,配置主要是Realm的管理认证
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("customRealm") CustomRealm customRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(customRealm);
return securityManager;
}
//将自己的验证方式加入容器
@Bean
public CustomRealm customRealm() {
return new CustomRealm();
}
//集成 thymeleaf-extras-shiro,可以在前端使用shiro语法
@Bean
public ShiroDialect getShiroDialect(){return new ShiroDialect();}
}
shiro异常处理配置:
package com.jay.SpringBootStudy8.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
@Configuration
public class ShiroExceptionConf {
@Bean
public SimpleMappingExceptionResolver resolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/noauth");
resolver.setExceptionMappings(properties);
return resolver;
}
}
3、自定义CustomRealm
package com.jay.SpringBootStudy8.config;
import com.jay.SpringBootStudy8.pojo.Permission;
import com.jay.SpringBootStudy8.pojo.Role;
import com.jay.SpringBootStudy8.pojo.SysUser;
import com.jay.SpringBootStudy8.service.PermissionService;
import com.jay.SpringBootStudy8.service.RoleService;
import com.jay.SpringBootStudy8.service.SysUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.stream.Collectors;
public class CustomRealm extends AuthorizingRealm {
@Autowired
private SysUserService sysUserService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
//授权,装配用户权限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// Subject subject = SecurityUtils.getSubject();
// Session session = subject.getSession();
// SysUser user = (SysUser) session.getAttribute("user");
//获取登录用户
SysUser sysUser = (SysUser) principalCollection.getPrimaryPrincipal();
List<Permission> permissions = sysUser.getPermissions();
List<Role> roles = sysUser.getRoles();
//添加角色和权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role role : roles) {
//添加角色
info.addRole(role.getName());
}
//添加权限
for (Permission perm : permissions) {
info.addStringPermission(perm.getCode());
}
return info;
}
//认证,验证用户的账户和密码
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
String username = userToken.getUsername();
SysUser user = sysUserService.getModelByUserName(username);
if (user == null) {
return null;//这里返回后会报出对应异常
} else {
List<Role> roles = roleService.getAllByUserId(user.getId());
user.setRoles(roles);
List<Integer> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList());
List<Permission> perms = permissionService.getAllByRoleIds(roleIds);
user.setPermissions(perms);
//盐值加密验证密码
String realmName = getName();
ByteSource credentialsSalt = ByteSource.Util.bytes(username);//这里的参数要给个唯一的;
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPwd(), credentialsSalt, realmName);
// 存入Shiro的Session,这里不是HttpSession,是Shiro独立的Session,
// 只能通过SecurityUtils.getSubject().getSession()获取
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("user", user);
return info;
}
}
}
4、登录Controller
package com.jay.SpringBootStudy8.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
//在templates目录下的页面只能通过controller来跳转
@Controller
public class IndexController {
@RequestMapping("/noauth")
public String unauthorized() {
return "unauthorized";
}
@RequestMapping({"/", "/login"})
public String login() {
return "login";
}
@RequestMapping("/logout")
public String logout() {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
@PostMapping("/loginHandler")
public String loginHandler(String name, String pwd, Model model) {
//MD5加密
ByteSource credentialsSalt = ByteSource.Util.bytes(name);
Object obj = new SimpleHash("MD5", pwd, credentialsSalt, 1);
String pwd2 = obj.toString();
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装登录数据
UsernamePasswordToken token = new UsernamePasswordToken(name, pwd2);
try {
//执行登录方法
subject.login(token);
return "redirect:/sys/main";
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用户名不存在");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密码错误");
return "login";
}
}
}
5、 数据库中权限表:permissions
Id Name Code -------------------------------------- 1 用户管理 users:mgr 2 角色管理 roles:mgr 3 权限管理 permissions:mgr 4 商品管理 products:mgr 5 图文管理 articles:mgr
6、前端需要整合
<div th:fragment="header">
<a th:href="@{/sys/main}">主页</a>
<span shiro:hasPermission="users:mgr">
<a th:href="@{/sys/users}">用户管理</a>
</span>
<span shiro:hasPermission="roles:mgr">
<a th:href="@{/sys/roles}">角色管理</a>
</span>
<span shiro:hasPermission="permissions:mgr">
<a th:href="@{/sys/permissions}">权限管理</a>
</span>
<span shiro:hasPermission="products:mgr">
<a th:href="@{/sys/products}">商品管理</a>
</span>
<span shiro:hasPermission="articles:mgr">
<a th:href="@{/sys/articles}">图文管理</a>
</span>
<span>
<a th:href="@{/logout}">注销</a>
</span>
</div>
引入fragment:<div th:insert="~{common/head :: header}"></div>,shiro前端提示需要引入html命名空间:xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
springboot+shiro实现自定义密码加密及验证(Bcrypt):https://blog.csdn.net/qq_21537671/article/details/107280447
shiro注解:https://blog.csdn.net/qi923701/article/details/75224554/
shiro thymeleaf:https://blog.csdn.net/qq_34579313/article/details/82024058
swagger引用包
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.5.10</version> </dependency>
访问:http://localhost:8091/swagger-ui.html就可以看到所有接口,具体使用方法百度。
浙公网安备 33010602011771号