SpringSecurity(安全)
- 导入依赖
<!--security依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--thymeleaf整合security-->
dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
- SecurityConfig.java
package com.zhb.springboot02.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;
//AOP:拦截器
//链式编程
@EnableWebSecurity //加上这个注解才生效
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//设置权限,首页所有人都可以访问,功能页只有相应权限的人才能访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限跳到登录页面
http.formLogin().loginPage("/toLogin");
//关闭跨站请求攻击的防护,默认开启,get请求可能会报404,所以要关闭
http.csrf().disable();
//开启注销功能,并跳到登录页,会把session和cookie都删除
http.logout().logoutSuccessUrl("/");
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这里从内存中认证作为例子,也可以从数据库中auth.jdbcAuthentication()
//用户就三个参数:姓名,密码,角色
//可以通过and()再添加一个用户
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("zhb")
.password("123456").roles("vip1")
.and()
.withUser("root")
.password("123").roles("vip1","vip2","vip3");
//当密码没加密就有可能会出现一个500错误:PasswodEncoder,认为你的密码不安全,因为可以反编译
//在security5.0+新增了很多加密方法,
//通过.passwordEncoder(new BCryptPasswordEncoder())设置加密的方式
//再通过.password(new BCryptPasswordEncoder().encode("123456"))进行编码
}
}
jdbc认证:
shiro
-
导入依赖:
<!--整合spring就不用添加这个包,否则会导致ShiroFilterFactoryBean这个找不到--> <!--<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.1</version> </dependency>--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency>
-
配置文件:shiro.ini
-
快速开始
//固定套路,通过工厂设置安全管理
Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager=factory.getInstance;
SecurityUtils.setSecurityManager(securityManager);
//具体操作
Subject currentUser=SecurityUtils.getSubject();//获取用户
Session session=currentUser.getSession();//获取session
if(!currentUser.isAuthenticated()){}//判断当前用户是否被认证
currentUser.getPrincipal();//获取当前用户的认证
currentUser.hasRole("admin");//判断当前用户是否是这个角色
currentUser.isPermitted("admin");//判断当前用户是否有这个权限
currentUser.louout();//注销
实际写项目:
shiro有三大对象:
- Subject:用户,currentUser
- SecurityManager: 用户管理
- Realm:连接数据
配置的话要倒着配,先连接数据,再设置用户管理,最后才进行用户一些登录或登出获取session的操作
-
UserRealm.java,用来编写查询的一些方法和认证授权的逻辑
首先得继承
AuthorizingRealm
这个类,重写doGetAuthorizationInfo
(授权),doGetAuthenticationInfo
(认证)两个方法package com.zhb.config; import com.zhb.service.EmpService; import org.apache.catalina.security.SecurityUtil; 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.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; public class UserRealm extends AuthorizingRealm { @Autowired EmpService empService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //授权操作 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //当ShiroConfig进行设置权限阻拦时就会跳到这么方法 //假如root为0,管理员为1,普通用户为2,下面这个操作就是代表对权限值是0进行授权放行 //而1和2就会被阻拦 //拿到当前登录对象 Subject user= SecurityUtils.getSubject(); //从这获取到认证传过来的授权值,这里是个object,获取过来是什么可以进行强转 String principal = (String)user.getPrincipal(); //设置当前用户的权限,是什么就是什么 info.addStringPermission(principal); return info; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取输入的用户和密码 UsernamePasswordToken userToken = (UsernamePasswordToken) token; //获取密码· List<String> passwords = empService.selectPassword(userToken.getUsername()); if (passwords == null && passwords.isEmpty()) { return null;//return null就会抛出UnknownAccountException异常 } //查到用户后设置session Subject currentUser = SecurityUtils.getSubject(); currentUser.getSession().setAttribute("loginUser",userToken.getUsername()); //密码认证,shiro来做,返回简单的加密方式 //第一个参数是principal,用来向授权传递参数,这里伪造一个“0”,实际应该通过数据库获取权限值 for (String password : passwords) { return new SimpleAuthenticationInfo("0", password, ""); } return null; } }
-
ShiroConfig.java:总配置,集成到spring的bean中
需要创建三个bean,注意要添加@Bean注解添加到spring容器中
- ShiroFilterFactoryBean
- DefaultWebSecurityManager
- UserRealm
package com.zhb.springboot02.config; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfig { @Bean //ShiroFilterFactoryBean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); //添加shiro的内置过滤器 /* anon:无需认证就可以访问 authc:必须认证才能访问 user:必须拥有“记住我”这个功能才能用 perms:拥有对某个资源的权限才能访问 role:拥有某个角色权限才能访问 */ //被拦截后,会自动跳到登录页面,但跟SpringSecurity不一样,它的login.html必须自己写 Map<String,String> filterMap=new LinkedHashMap<>(); filterMap.put("/user/add/","anon");//这个路径所有人都能访问 filterMap.put("/user/update","perms[0]");//这个请求的操作只有权限为0的用户可以做 bean.setFilterChainDefinitionMap(filterMap); //设置登录跳转的请求 bean.setLoginUrl("/index"); //设置未授权后会跳转的请求 bean.setUnauthorizedUrl("/noauth"); return bean; } //DafaultWebSecurityManager:第二步 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联realm securityManager.setRealm(userRealm); return securityManager; } //创建 realm对象,需要自定义:第一步 @Bean public UserRealm userRealm(){ return new UserRealm(); } }
在controller中验证登录:
@RequestMapping("/login") public String login(String username, String password, Model model) { Subject currentUser = SecurityUtils.getSubject(); //对用户名密码进行加密封装 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //登陆验证 try { currentUser.login(token); return "index"; } catch (UnknownAccountException e) {//用户名不存在 model.addAttribute("msg", "用户名不存在"); return "login"; } catch (IncorrectCredentialsException e) {//密码错误 model.addAttribute("msg", "密码错误"); return "login"; } }
thymeleaf整合shiro:
-
导入依赖
<!-- thymeleaf整合shiro --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
-
可以在ShiroConfig中配置一下,注册个bean
@Bean //配置ShiroDialect,用来整合shiro和thymeleaf public ShiroDialect getShiroDialect(){ return new ShiroDialect(); }
-
html页面使用
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" > <head> <meta charset="UTF-8"> <title>Thymeleaf整合Shiro</title> </head> <body> <!--从session中获取值,没有值就显示登录按钮--> <div th:if="${session.loginUser==null}"> <a th:href="@{/login}">登录</a> </div> <!--用户拥有0这个权限才会显示删除这个链接--> <div shiro:hasPermission="0"> <a th:href="@{user/delete}">删除</a> </div> <!--用户拥有1这个权限才会显示查找这个链接--> <div shiro:hasPermission="1"> <a th:href="@{user/update}">查找</a> </div> </body> </html>