第一步:引入springSecurity。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
默认的配置是拦截所有的路径。
第二步:写配置类
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* authorizeRequests:所有security全注解配置实现的开端。表示开始说明需要的权限
* 需要的权限分两部分,第一部分是拦截的路径,第二部分访问路径需要的权限
* antMatchers:表示拦截路径,permitAll表示任何权限都可以使用,直接放行所有
* anyRequest():任何的请求,authenticated():认证后才能访问
* .and().csrf().disable():固定写法,表示使csrf拦截失效
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
}
这个适配器实现了一些空的方法。这段可以作为模板贴上去的。
-------------------------------------------------------------------01-----------------------------------------02----------------03-----------------------------------
springboot是把web.xml拿掉的。
web.xml是初始化的,现在这个替代了。
---------------------------------------------------------------------------04-----------------------------------------------------------------------
加密的网址:https://www.jianshu.com/p/89c4c476e189
引入加密算法:
第一步:
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
@Bean
public IdWorker idWorkker(){
return new IdWorker(1, 1);
}
@Bean
public BCryptPasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
}
第二步:注入和使用,对密码进行加密存入到数据库。
public void add(Admin admin) {
admin.setId( idWorker.nextId()+"" ); //雪花分布式ID生成器
admin.setPassword(encoder.encode(admin.getPassword()));//密码加密
adminDao.save(admin);
}
第三步:测试
---------------------------------------------------------------------------05-----------------------------------------------------------------------
写登陆:
第一步:
public Admin login(Admin admin) {
//先根据用户名查询对象.
Admin admin_login = adminDao.findByLoginname(admin.getLoginname());
//拿数据库中的密码和用户输入的密码匹配是否相同
if(admin_login!=null&&encoder.matches(admin.getPassword(),admin_login.getPassword())){
//保证数据库中的密码和用户输入的密码是一致的
//登录成功
return admin_login;
}
//登录失败
return null;
}
知识点:
@RequestBody:可以转为对象也可以转为map。
第二步:写controller
-----------------------------------------------------------------------------06----------------------------------------------------------------------------
用户的注册登陆的改造:
第一步:加密关键代码
/**
* 增加
* @param user
*/
public void add(User user) {
user.setId( idWorker.nextId()+"" );
//密码加密
user.setPassword(encoder.encode(user.getPassword()));
user.setFollowcount(0);//关注数
user.setFanscount(0);//粉丝数
user.setOnline(0L);//在线时长//
user.setRegdate(new Date());//注册日期
user.setUpdatedate(new Date());//更新日期
user.setLastdate(new Date());//最后登陆日期
userDao.save(user);
}
第二步:登陆关键代码
public User login(String mobile,String password) {
User user = userDao.findByMobile(mobile);
if(user!=null && encoder.matches(password,user.getPassword())){
return user;
}
return null;
}
---------------------------------------------------------------------------07-----------------------------------------------------------------------
常见的认证机制:
1.每次都带上用户名和密码,无状态的。
2.CooKie Auth:登陆的信息在浏览器存在cookie,服务器存在session中。安卓ios什么的不方便。手机端现在越来越流行了。
3.OAuth:
4.Token Auth:
服务端是不存的用JWT算法。到时候我解密就可以了。
这个token的生成策略我们用的是JWT。
---------------------------------------------------------------------------08-----------------------------------------------------------------------
token的优点:
---------------------------------------------------------------------------09-----------------------------------------------------------------------
JWT生成tokrn的规则:
头部,载荷,签名。
头部:
载荷:
签名:对头部和载荷进行加密。
最后一点JWT是后台签发的。三部分组成。
---------------------------------------------------------------------------10-----------------------------------------------------------------------
JJWT:
第一步:导入坐标在common模块注意是在common模块里面。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
第二步:
List<Object> roles=new ArrayList<>();
roles.add("role1");
roles.add("role2");
JwtBuilder jwtBuilder = Jwts.builder()
//用户的id用户名
.setId("666") .setSubject("小马")
.setIssuedAt(new Date())//何时登陆的
.signWith(SignatureAlgorithm.HS256,"wmlw")//头部信息 后面的是加的盐
.setExpiration(new Date(new Date().getTime()+60000))
.claim("roles",roles);
System.out.println(jwtBuilder.compact());
这个set是按照这个标准set的:
----------------------------------------------------------------------------------11---------------------------------------------------------------------------------
解析JWT:
public static void main(String[] args) {
//Claims里面就是key和value
Claims claims = Jwts.parser().setSigningKey("wmlw")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_pqawiLCJpYXQiOjE1ODAzNjA5NzksImV4cCI6MTU4MDM2MTAzOSwicm9sZXNBZGQiOlsicm9sZTEiLCJyb2xlMiJdfQ.Lx9C8olEcY29NHSx90Q0aifA1JjwzwyyKpWkadzk2eI")
.getBody();
System.out.println("用户id"+claims.getId());
System.out.println("用户名"+claims.getSubject());
System.out.println("登录时间"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getIssuedAt()));
System.out.println("过期时间"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getExpiration()));
System.out.println("角色"+claims.get("rolesAdd"));
}
---------------------------------------------------------------------------12-----------------------------------------------------------------------
token的过期时间:
同上。
---------------------------------------------------------------------------13-----------------------------------------------------------------------
添加自定义的键值对:
---------------------------------------------------------------------------14-----------------------------------------------------------------------
token工具类:
第一步:拷贝JwtUtils:
注意下这个微服务的配置文件是引用它的微服务的配置文件读取的。没毛病。
第二步:
必传的信息:id,
---------------------------------------------------------------------------15-----------------------------------------------------------------------
admin登陆生成token:
第一步:我们写加盐的yml注意在哪个模块里面。
第二步:在启动类加Jwt工具。
第三步:写代码
用户 角色 权限 都是多对多
@PostMapping("/login")
public Result login(@RequestBody Admin admin) {
Admin adminLogin = adminService.login(admin);
if (adminLogin == null) {
return new Result(false, StatusCode.ERROR, "登录失败");
}
//是的前后端可以通话的操作。采用JWT操作
//生成令牌
// List<Object> roles = new ArrayList<>();
// roles.add("role1");
// roles.add("role2");
String token = jwtUtil.createJWT(adminLogin.getId(), adminLogin.getLoginname(), "admin");
Map<String, Object> map = new HashMap<>();
map.put("token", token);
map.put("role", "admin");
return new Result(true, StatusCode.OK, "登录成功", map);
// return new Result(true, StatusCode.OK, "登录成功", "登陆凭证");
}
测试登陆:
---------------------------------------------------------------------------16-----------------------------------------------------------------------
我们假设一个场景:删除的功能。我们要把token放在请求头里面。
第一步:request是一次请求,拿到request才能拿到请求头。
测试:
先登陆:
请求:
--------------------------------------------------------------------------17----------18-------------------------------------------------------------
用拦截器写:
其实也可以用springSecurity。
jdk1.8的好处:
第一步写拦截器:
拦截器都放行,不管是什么,在请求的request写入角色。
第二步:写配置configuration
相当于配置xml。
-----------------------------------------------------------------------19------20----------------------------------------------------------------
拦截器的验证测试:
第一步:改造userService
public void deleteById(String id) {
// String header = request.getHeader("Authorization");
// if (header == null || header.equals("")) {
// throw new RuntimeException("权限不足!");
// }
// if (!header.startsWith("Bearer ")) {
// throw new RuntimeException("权限不足");
// }
// //得到token
// String token = header.substring(7);
// try {
// Claims claims = jwtUtil.parseJWT(token);
// String roles = (String) claims.get("roles");
// if (roles == null && !"admin".equals(roles)) {
// throw new RuntimeException("权限不足");
// }
// } catch (Exception e) {
// throw new RuntimeException("权限不足");
// }
String token=(String)request.getAttribute("claims_admin");
if(token==null || "".equals(token)){
throw new RuntimeException("权限不足");
}
userDao.deleteById(id);
}
测试:略。
--------------------------------------------------21---------------------------------------------
问答的token问题。
登陆才能问问题。
第一步:在UserService。
@PostMapping("/login")
public Result login(@RequestBody User user){
user=userService.login(user.getMobile(),user.getPassword());
if(user==null){
return new Result(false,StatusCode.ERROR,"登录失败");
}
String token = jwtUtil.createJWT(user.getId(), user.getMobile(), "user");
Map<String,Object> map =new HashMap<>();
map.put("token",token);
map.put("roles","user");
return new Result(true,StatusCode.OK,"登录成功",map);
// return new Result(true,StatusCode.OK,"登录成功","登陆成功");
}
第二步:在问答里面验证
yml导入配置:
第三步:将过滤器导入
第四步:
/**
* 增加
* @param problem
*/
@RequestMapping(method=RequestMethod.POST)
public Result add(@RequestBody Problem problem ){
String token=(String)request.getAttribute("claims_user");
if(token ==null || "".equals(token)){
return new Result(false,StatusCode.ACCESSERROR,"权限不足");
}
problemService.add(problem);
return new Result(true,StatusCode.OK,"增加成功");
}
--------------------------------------------------22---------------------------------------------