week 8.31-9.6
- | Study-update |
---|---|
-Mon | element-ui 前端表单校验 |
- | - |
- | Study-update |
-Thu | 动态代理复习 |
-Fri | 工厂模式练习 security登陆表单 |
-Sat | 方法安全权限 |
-Sun | 从数据库验证账户密码 |
8.31 Monday
登陆表单前端页面
Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可
<template>
<div>
<el-form :rules="rules" v-model="loginForm" class="loginContainer">
<h1 class="loginTitle">登陆系统</h1>
<el-form-item prop="username">
用户名:
<el-input type="text" v-model="loginForm.username" auto-complete="off" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item prop="password">
用户名:
<el-input type="text" v-model="loginForm.password" auto-complete="off" placeholder="请输入密码"></el-input>
</el-form-item>
<el-checkbox v-model="checked"></el-checkbox>
<el-button type="primary" style="width: 100%">登陆</el-button>
</el-form>
</div>
</template>
<script>
export default {
name: "Login",
data() {
return {
loginForm: {username: '', password: ''},
rules: {
username: [
{required: true, message: '请输入用户名', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'}
]
},
checked: true
}
}
}
</script>
<style>
.loginContainer{
border: 1px solid silver;
border-radius: 15px;
background-clip: padding-box;
margin: 180px auto;
width: 350px;
padding: 35px 35px 15px 35px;
background: white;
box-shadow: 0 0 25px silver;
}
.loginTitle{
color: gray;
margin: 0px auto 0px auto;
text-align: center;
}
</style>
9.3 Thursday
书本工厂接口
package com.maaoooo.dynamicProxy;
/**
* @author lzr
* @date 2020/9/3 10:53:12
* @description 出售书的接口
*/
public interface SellBooks {
void sellBook(double price);
}
书本工厂
```java
package com.maaoooo.dynamicProxy;
/**
* @author lzr
* @date 2020/9/3 10:53:57
* @description 书本工厂类
*/
public class StroyBookFactory implements SellBooks {
public void sellBook(double price) {
System.out.println("购买了故事书,价格为:"+price);
}
}
香水工厂接口
```java
package com.maaoooo.dynamicProxy;
/**
* @author lzr
* @date 2020/9/3 10:50:59
* @description 出售香水的接口
*/
public interface SellPerfume {
void sellPerfume(double price);
}
香水工厂
package com.maaoooo.dynamicProxy;
/**
* @author lzr
* @date 2020/9/3 10:51:39
* @description 香奈儿香水工厂类
*/
public class ChanelFactrory implements SellPerfume {
public void sellPerfume(double price) {
System.out.println("购买香水,价格为:"+price);
}
}
代理工厂
package com.maaoooo.dynamicProxy;
import org.springframework.util.StringUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author lzr
* @date 2020/9/3 10:55:13
* @description 代理工厂
*/
public class SellProxyFactory implements InvocationHandler {
private Object realObject;
public SellProxyFactory(Object realObject) {
this.realObject = realObject;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("收取手续费10%");
Object obj = method.invoke(realObject, args);
double price = Double.parseDouble(args[0].toString());
System.out.println("最终价格为:"+price*1.1);
return obj;
}
}
购买者测试
package com.maaoooo.dynamicProxy;
import java.lang.reflect.Proxy;
/**
* @author lzr
* @date 2020/9/3 10:54:38
* @description 测试购买
*/
public class Buyer {
public static void main(String[] args) {
ChanelFactrory chanelFactrory = new ChanelFactrory();
SellProxyFactory perfumeSeller = new SellProxyFactory(chanelFactrory);
SellPerfume perfume = (SellPerfume) Proxy.newProxyInstance(chanelFactrory.getClass().getClassLoader(), chanelFactrory.getClass().getInterfaces(), perfumeSeller);
perfume.sellPerfume(2000);
StroyBookFactory stroyBookFactory = new StroyBookFactory();
SellProxyFactory bookSeller = new SellProxyFactory(stroyBookFactory);
SellBooks sellBook = (SellBooks) Proxy.newProxyInstance(stroyBookFactory.getClass().getClassLoader(), stroyBookFactory.getClass().getInterfaces(), bookSeller);
sellBook.sellBook(1000);
}
}
运行结果
主要
代理工厂实现InvocationHandler 接口。实现invoke()方法
invoke() 方法有3个参数:
- Object proxy:代理对象
- Method method:真正执行的方法
- Object[] agrs:调用第二个参数 method 时传入的参数列表值
生成时用到Proxy类
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
实例化代理对象时,需要传入3个参数:
- ClassLoader loader:加载动态代理类的类加载器
- Class<?>[] interfaces:代理类实现的接口,可以传入多个接口
- InvocationHandler h:指定代理类的「调用处理程序」,即调用接口中的方法时,会找到该代理工厂h,执行invoke()方法
9.4 Friday
用工厂模式提供加减乘除的运算类
package factory;
/**
* @author lzr
* @date 2020/9/4 09:43:55
* @description 算法接口
*/
public interface Algorithm {
public double getResult(double a,double b);
}
package factory;
/**
* @author lzr
* @date 2020/9/4 09:44:42
* @description 加法实现
*/
public class Add implements Algorithm {
public double getResult(double a, double b) {
return a+b;
}
}
package factory;
/**
* @author lzr
* @date 2020/9/4 09:45:27
* @description 减法实现
*/
public class Sub implements Algorithm {
public double getResult(double a, double b) {
return a-b;
}
}
package factory;
/**
* @author lzr
* @date 2020/9/4 09:45:47
* @description 乘法实现
*/
public class Mul implements Algorithm {
public double getResult(double a, double b) {
return a*b;
}
}
package factory;
/**
* @author lzr
* @date 2020/9/4 09:46:17
* @description 除法实现
*/
public class Division implements Algorithm {
public double getResult(double a, double b) {
if(a==0){
throw new RuntimeException("除数不能为0");
}
return a/b;
}
}
package factory;
/**
* @author lzr
* @date 2020/9/4 09:47:25
* @description 算法工厂
*/
public class ComputeFactory {
public static Algorithm getAlgorithm(String symbol) {
if ("+".equals(symbol)) {
return new Add();
} else if ("-".equals(symbol)) {
return new Sub();
} else if ("*".equals(symbol)) {
return new Mul();
} else if ("/".equals(symbol)) {
return new Division();
}
throw new RuntimeException("符号错误");
}
}
package factory;
/**
* @author lzr
* @date 2020/9/4 09:51:49
* @description 测试
*/
public class FactoryTest {
public static void main(String[] args) {
Algorithm addAlgorithm = ComputeFactory.getAlgorithm("+");
System.out.println(addAlgorithm.getResult(12.4, 10));
Algorithm subAlgorithm = ComputeFactory.getAlgorithm("-");
System.out.println(subAlgorithm.getResult(20, 15));
Algorithm MulAlgorithm = ComputeFactory.getAlgorithm("*");
System.out.println(MulAlgorithm.getResult(10, 10));
Algorithm divisionAlgorithm = ComputeFactory.getAlgorithm("/");
System.out.println(divisionAlgorithm.getResult(10, 2));
}
}
security登陆表单
/**
* @author lzr
* @date 2020 09 03 20:28
* @description 登陆表单的配置
*/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("123").roles("admin")
.and()
.withUser("xiaoliu").password("456").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("admin", "user")
.and()
.formLogin()
.loginProcessingUrl("/doLogin")//登陆接口
.loginPage("/login")//跳转到登陆页面的接口
.successHandler(new AuthenticationSuccessHandler() { //登陆成功处理
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json:charset=UTF-8");
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", authentication.getPrincipal());
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() { //登陆失败处理
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8"); //设置json
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 401);
if (e instanceof LockedException) {
map.put("msg", "账户被锁定,登陆失败!");
} else if (e instanceof BadCredentialsException) {
map.put("msg", "用户名或密码输入错误!");
} else if (e instanceof DisabledException) {
map.put("msg", "账户被禁用");
} else if (e instanceof AccountExpiredException) {
map.put("msg", "账户过期,登陆失败!");
} else if (e instanceof CredentialsExpiredException) {
map.put("msg", "密码过期,登陆失败!");
} else {
map.put("msg", "登陆失败");
}
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8"); //设置json
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "注销成功!");
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll()
.and()
.csrf().disable();
}
}
9.5 Saturday
方法安全,给单个方法加上安全权限控制。
首先在secrutiyConfig上加注解,开启该功能
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
编写service作为测试用例
/**
* @author lzr
* @date 2020 09 06 10:15
* @description
*/
@Service
public class MethodsService {
@PreAuthorize("hasRole('admin')")
public String admin(){
return "hello admin";
}
@Secured("ROLE_user")
public String user(){
return "hello user";
}
@PreAuthorize("hasAnyRole('admin','user')")
public String hello(){
return "hello hello";
}
}
这样访问对应方法必须有相应权限。
9.6 Saturday
创建测试数据库
3个表 user role 和 user-roles关系表
先编写两个实体类
User
**
* @author lzr
* @date 2020 09 06 10:50
* @description
*/
@Data
public class User implements UserDetails { //需实现UserDetails
private Integer id;
private String username;
private String password;
private boolean enabled;
private boolean locked;
private List<Role> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() { //返回所有的角色
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
}
return authorities;
}
@Override
public boolean isAccountNonExpired() {//是否未过期
return true;
}
@Override
public boolean isAccountNonLocked() {//是否未锁定
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {//密码是否未过期
return true;
}
}
role
/**
* @author lzr
* @date 2020 09 06 10:50
* @description
*/
@Data
public class Role {
private Integer id;
private String name;
private String nameZh;
}
编写UserService
/**
* @author lzr
* @date 2020 09 06 11:34
* @description
*/
@Service
public class UserService implements UserDetailsService {//实现UserDetailsService
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String usernmae) throws UsernameNotFoundException {//在此验证账户,密码会根据user自动验证
User user = userMapper.loadUserByUsername(usernmae);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
user.setRoles(userMapper.getUserRolesById(user.getId()));//设置角色
return user;
}
}
编写UserMapper
/**
* @author lzr
* @date 2020 09 06 11:34
* @description
*/
@Mapper
public interface UserMapper {
User loadUserByUsername(String usernmae);
List<Role> getUserRolesById(Integer id);
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.maaoooo.security_db_demo.mapper.UserMapper">
<select id="loadUserByUsername" resultType="com.maaoooo.security_db_demo.entity.User" parameterType="String">
select * from security.user where username=#{username}
</select>
<select id="getUserRolesById" resultType="com.maaoooo.security_db_demo.entity.Role">
select * from security.role where id in (select rid from security.user_role where uid=#{id})
</select>
</mapper>
SecurityConfig
/**
* @author lzr
* @date 2020 09 06 11:58
* @description
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin").hasRole("admin")
.antMatchers("/dba").hasRole("adb")
.antMatchers("/user").hasRole("user")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.csrf().disable();
}
@Autowired
private UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
编写controller测试
/**
* @author lzr
* @date 2020 09 06 12:07
* @description
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello world!";
}
@GetMapping("/adb")
public String adb(){
return "adb";
}
@GetMapping("/admin")
public String admin(){
return "admin";
}
@GetMapping("/user")
public String user(){
return "user";
}
}