对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。
-
Sping Data 官网:https://spring.io/projects/spring-data
-
数据库相关的启动器 :可以参考官方文档:https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
1.新建一个项目引入基础模块:
2.编写yaml配置文件连接数据库
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
password: 1234
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&haracterEncoding=UTF-8&serverTimezone=UTC
username: root
3.测试
@SpringBootTest
class Springboot05DataApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() throws SQLException {
//查看默认数据源
System.out.println(dataSource.getClass());
//连接数据库
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
}
HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀。
1.3JDBCTemplate
xxxxTemplate:spring boot已经配置好的模板bean,拿来即用CRUD。
源码位置:
JdbcTemplate主要提供以下几类方法:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句
- query方法及queryForXXX方法:用于执行查询相关语句
- call方法:用于执行存储过程、函数相关语句
测试:
@RestController
public class JDBCController {
@Autowired
JdbcTemplate jdbcTemplate;
//查询数据库的全部信息
//我们没写实体类就用一个万能的Map
@GetMapping("/list")
public List<Map<String,Object>> query(){
String sql="select * from mybatis.user";
List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
return mapList;
}
@GetMapping("/addlist")
public String add(){
String sql="insert into mybatis.user (id,user.name,pwd) values(1,'嘿嘿嘿','9uidj')";
jdbcTemplate.update(sql);
return "ok";
}
@GetMapping("/deletelist/{id}")
public String delete(@PathVariable int id){
String sql="delete from mybatis.user where id=?";
jdbcTemplate.update(sql,id);
return "ok1";
}
@GetMapping("/updatelist/{id}")
public String update(@PathVariable int id){
String sql="update mybatis.user set user.name=?,pwd=? where id="+id;
Object[] objects = new Object[2];
objects[0]="啦啦啦";
objects[1]="wef";
jdbcTemplate.update(sql,objects);
return "ok2";
}
}
Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。
Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。
Github地址:https://github.com/alibaba/druid/
首先要导入依赖:
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
spring:
datasource:
# 指定数据源
type: com.alibaba.druid.pool.DruidDataSource
测试结果:
一些配置:其中filters: stat,wall,log4j是其强大之处
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
password: 1234
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&haracterEncoding=UTF-8&serverTimezone=UTC
username: root
type: com.alibaba.druid.pool.DruidDataSource
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
2.2监控的配置类
在config包下建一个DuridConfig 配置类
@Configuration
public class DruidConfig {
//与yaml配置文件绑定
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource DuridDatasource(){
return new DruidDataSource();
}
//后台监控,相当于web.xml
//因为springboot内置了servlet,没有web.xml,所以替代方法就是去配置一个类
@Bean
public ServletRegistrationBean StatViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
//后台需要有人登录,账号密码设置
HashMap<String, String> initParameters = new HashMap<>();
//增加配置
initParameters.put("loginUsername","admin");
initParameters.put("loginPassword","1234");//登陆的key是固定的,loginUsername、loginPassword
//允许谁访问
initParameters.put("allow","");
//禁止谁访问
initParameters.put("moli","192.168.99.123");
bean.setInitParameters(initParameters);//设置初始化参数
return bean;
}
}
测试结果:
再运行一下前面查询数据库的请求/list,刷新发现已经被druid监控:
过滤的配置类:
@Bean
public FilterRegistrationBean WebStatFilter(){
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
bean.setFilter(new WebStatFilter());
Map<String, String> initParameters=new HashMap<>();
//这些东西不进行统计
initParameters.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParameters);
return bean;
}
首先导入整合包
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.2version>
dependency>
连接数据库:
实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
mapper接口:
@Repository//代表被spring接管
@Mapper//这个注解表示这是一个mybatis的mapper接口
//@MapperScan("com.moli.mapper")用来扫描包,发现mapper接口,用在主类上
public interface UserMapper {
int add(User user);
int delete(@Param("id")int id);
int update(User user);
List<User> query();
User queryById(@Param("id") int id);
}
application.yaml配置:
#整合mybatis
mybatis:
type-aliases-package: com.moli.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
在resource包下新建mybatis包,再建mapper包—UserMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.moli.mapper.UserMapper">
<select id="query" resultType="User">
select * from mybatis.user
select>
<select id="queryById" resultType="User">
select * from mybatis.user where id=#{id}
select>
<insert id="add" parameterType="User">
insert into mybatis.user (id,user.name,pwd) values(#{id},#{name},#{pwd})
insert>
<update id="update" parameterType="User">
update mybatis.user set user.name=#{name},pwd=#{pwd} where id=#{id}
update>
<delete id="delete" parameterType="int">
delete from mybatis.user where id=#{id}
delete>
mapper>
在controller包中测试
@RestController
public class UserController {
@Autowired
UserMapper userMapper;
@RequestMapping("/queryuser")
public List<User> a(){
List<User> query = userMapper.query();
return query;
}
@RequestMapping("/queryid/{id}")
public User byid(@PathVariable int id){
User user = userMapper.queryById(id);
return user;
}
@RequestMapping("/adduser")
public int adduser(){
int add = userMapper.add(new User(2,"哈哈哈","qwdfb"));
return add;
}
@RequestMapping("/updateuser")
public int updateuser(){
int update = userMapper.update(new User(7, "嗷嗷嗷", "wjs098987"));
return update;
}
@RequestMapping("/del")
public int del(){
int delete = userMapper.delete(9);
return delete;
}
}
在 Web 开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的第一天就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,影响应用的发布进程。
Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求。
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
- WebSecurityConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式 @EnableXXX开启某个功能
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制):
“认证”(Authentication)
身份验证,如用户名/用户ID和密码,以验证您的身份。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
4.2环境搭建
导入静态资源:
导入thymeleaf依赖:
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
dependency>
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-java8timeartifactId>
dependency>
并关闭thymeleaf缓存:
spring.thymeleaf.cache=false
编写controller确保页面能够跳转:
@Controller
public class RouterController {
@RequestMapping({"/" ,"/index"})
public String toindex(){
return "index";
}
@RequestMapping("/level1/{id}")
public String l1(@PathVariable int id){
return "views/level1/"+id;
}
@RequestMapping("/level2/{id}")
public String l2(@PathVariable int id){
return "views/level2/"+id;
}
@RequestMapping("/level3/{id}")
public String l3(@PathVariable("id") int id){
return "views/level3/"+id;
}
@RequestMapping("/toLogin")
public String tologin(){
return "views/login";
}
}
首页:
4.3用户认证和授权
官网:https://spring.io/projects/spring-security
引入启动器:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
//编程思想: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();
//开启记住我功能,cookie
http.rememberMe();
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常从数据库读取,但没有连接数据库就直接从内存(inMemoryAuthentication())读取更快
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("铭").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("桑").password(new BCryptPasswordEncoder().encode("789")).roles("vip3");
}
//报错----There is no PasswordEncoder mapped for the id "null"
//解决----passwordEncoder(new BCryptPasswordEncoder())对密码进行编码
}
//定制登录页
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login").usernameParameter("name").passwordParameter("pwd");
//自定义记住我
http.rememberMe().rememberMeParameter("remember");
<div class="field">
<input type="checkbox" name="remember"/>记住我
div>
4.4注销及权限控制
添加注销按键:
//注销,并调转到首页
http.logout().logoutSuccessUrl("/");
//假如登出报了404页面错误,就添加如下
//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求.而我们登出是get所以会报404
http.csrf().disable();
我们现在又来一个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有就是,比如用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!
导入整合包:
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-springsecurity5artifactId>
<version>3.0.4.RELEASEversion>
dependency>
在index.html中导入命名空间:
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
菜单根据用户的动态实现:
测试结果:
Apache下的Shiro是一个强大且易用的Java安全框架,可以完成身份验证、授权、密码和会话管理。Shiro 不仅可以用在 JavaSE 环境中,也可以用在 JavaEE 环境中。
官网: http://shiro.apache.org/
功能:
Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情;
Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web支持,可以非常容易的集成到Web环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。
从外部看:
三大对象:Subject用户、SecurityManager管理所有用户、Realm连接数据
Subject:主体,代表了当前“用户”,应用代码直接交互的对象是Subject,与当前应用交互的任何东西都是Subject,如人,网络爬虫,机器人等是抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者。
SecurityManager:安全管理器,即所有与安全有关的 *** 作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器。
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行 *** 作;可以把Realm看成DataSource,即安全数据源。
最简单的一个Shiro应用-----------应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
5.2快速入门
GitHub地址:
https://gitcode.net/mirrors/apache/shiro?utm_source=csdn_github_accelerator
1.建一个maven父工程,删掉不必要的部分scr;创建一个普通的Maven子工程
2.去github中/samples/quickstart里拿到pom.xml、 log4j.properties、shiro.ini、Quickstart.java
<dependencies>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.5.3version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<version>1.7.26version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.26version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
dependencies>
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
# General Apache libraries
log4j.logger.org.apache=WARN
# Spring
log4j.logger.org.springframework=WARN
# Default Shiro logging
log4j.logger.org.apache.shiro=INFO
# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Quickstart {
private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
public static void main(String[] args) {
DefaultSecurityManager securityManager = new DefaultSecurityManager();
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
securityManager.setRealm(iniRealm);
SecurityUtils.setSecurityManager(securityManager);
//获得当前对象subject
Subject currentUser = SecurityUtils.getSubject();
//通过当前对象拿到session
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")) {
log.info("Retrieved the correct value! [" + value + "]");
}
// 判断当前用户是否被认证
if (!currentUser.isAuthenticated()) {
//Token令牌
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
token.setRememberMe(true);//记住我
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. " +
"Please contact your administrator to unlock it.");
}
catch (AuthenticationException ae) {
//unexpected condition? error?
}
}
//print their identifying principal (in this case, a username):
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
//test a role:
if (currentUser.hasRole("schwartz")) {
log.info("May the Schwartz be with you!");
} else {
log.info("Hello, mere mortal.");
}
//粗粒度 test a typed permission (not instance-level)
if (currentUser.isPermitted("lightsaber:wield")) {
log.info("You may use a lightsaber ring. Use it wisely.");
} else {
log.info("Sorry, lightsaber rings are for schwartz masters only.");
}
//细粒度 a (very powerful) Instance Level permission:
if (currentUser.isPermitted("winnebago:drive:eagle5")) {
log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +"Here are the keys - have fun!");
} else {
log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}
//all done - log out!
currentUser.logout();
System.exit(0);
}
}
5.3spring boot中集成
1.先导入thyme leaf依赖和shiro整合springbooot的包
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
dependency>
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-java8timeartifactId>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.8.0version>
dependency>
2.编写配置类
@Configuration
public class ShiroConfig {
//3.shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("security") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
//2.DefaultWebSecurityManager
@Bean(name = "security")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm对象
securityManager.setRealm(userRealm);
return securityManager;
}
//1.创建Realm对象,需要自定义类
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
3.UserRealm类
public class UserRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("doGetAuthorizationInfo");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("doGetAuthenticationInfo");
return null;
}
}
5.4登录拦截
1.四个页面:index.html、add.html、update.html、login.html
<p th:text="${msg}">p>
<a th:href="@{/add}">adda> | <a th:href="@{/update}">updatea>
<h1>登录h1>
<hr>
<form action="">
<p>用户名:<input type="text" name="name">p>
<p>密码:<input type="text" name="password">p>
<p>提交<input type="submit" name="submit">p>
form>
2.controller
@Controller
public class testcontroller {
@RequestMapping({"/","/index"})
public String index(Model model){
model.addAttribute("msg","hello");
return "index";
}
@RequestMapping("/add")
public String add(){
return "user/add";
}
@RequestMapping("/update")
public String update(){
return "user/update";
}
@RequestMapping("/tologin")
public String login(){
return "login";
}
}
3.在ShiroConfig
中的getShiroFilterFactoryBean
方法中添加如下配置:
- anon: 无需认证就可以访问
- authc: 必须认证了才能访问
- user: 必须拥有 记住我 功能才能用
- perms: 拥有对某个资源的权限才能访问
- role: 拥有某个角色权限
//需要认证了才能够访问
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/add","authc");
filterChainDefinitionMap.put("/update","authc");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//没认证就跳转到登陆页面
bean.setLoginUrl("/tologin");
5.5用户认证
1.在Controller中编写用户提交表单之后处理
@RequestMapping("/loginafter")
public String loginafter(String name,String password,Model model){
//获取一个用户
Subject subject = SecurityUtils.getSubject();
//封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
try{
subject.login(token);//登录
return "index";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码不正确");
return "login";
}catch (LockedAccountException e){
model.addAttribute("msg","用户被锁");
return "login";
}
}
2.login.html的修改
3.用户认证编写UserRealm中的认证(doGetAuthenticationInfo)
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//用户名,密码---伪造数据库
String name ="root";
String password="1234";
//用户名认证
UsernamePasswordToken userToken = (UsernamePasswordToken)authenticationToken;
if (!userToken.getUsername().equals(name)){
return null;//抛出异常
}
//密码认证shiro做,防止密码泄露
//也可以用md5加密,md5盐值加密
return new SimpleAuthenticationInfo("",password,"");
}
测试结果:
5.6整合mybatis
1.导入依赖:
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.2version>
dependency>
2.连接数据库,并配置配置文件(详情参考本文章第3小块—整合mybatis)
3.实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
4.mapper接口
@Repository
@Mapper
public interface UserMapper {
public User queryByName(String name);
}
5.resource里的UserrMapper.xml
<mapper namespace="com.moli.mapper.UserMapper">
<select id="queryByName" parameterType="String" resultType="User">
select * from mybatis.user where user.name=#{name}
select>
mapper>
6.service
public interface UserService {
public User queryByName(String name);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserrMapper userrMapper;
@Override
public User queryByName(String name) {
return userrMapper.queryByName(name);
}
}
7.测试
@SpringBootTest
class Springboot08Shiro1ApplicationTests {
@Autowired
UserServiceImpl userService;
@Test
void contextLoads() {
System.out.println(userService.queryByName("嘿嘿嘿"));
}
}
8.修改UserRealm
5.7授权
1.config
2.controller增加视图跳转
@RequestMapping("/noauth")
@ResponseBody
public String Unauthorized(){
return "未授权";
}
3.UserRealm:
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("add");
return info;
}
任何一个数据库的用户都可以访问add:
4.数据库增加一个perms字段,并修改对应的实体类,增加权限后,只有有权限的用户才能访问add、update
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//info.addStringPermission("add");
//获取当前对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User)subject.getPrincipal();//获取user
info.addStringPermission(currentUser.getPerms());
return info;
}
5.8thymeleaf
1.导入thymeleaf
<dependency>
<groupId>com.github.theborakompanionigroupId>
<artifactId>thymeleaf-extras-shiroartifactId>
<version>2.0.0version>
dependency>
引入thymeleaf是为了让有add权限的,只能看到add链接。
需要配置一下在shiroConfig中:
//thymeleaf
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
2.得到session
3.index.html
<h1>首页h1>
<p th:text="${msg}">p>
<div th:if="${session.loginuser==null}">
<a th:href="@{/tologin}">登陆a>
div>
<hr>
<div shiro:hasPermission="add">
<a th:href="@{/add}">adda>
div>
<div shiro:hasPermission="update">
<a th:href="@{/update}">updatea>
div>
测试结果:
- 模板:别人写好的我们加以改进
- 框架:组件自己动手拼接,bootstrap、Layui、semantic-ui、x-admin
步骤:
- 前端首先确定页面长什么样子,需要什么数据
- 设计数据库
- 前端能够独立运行
- 数据接口如何对接
- 前后端联调测试
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)