欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)全過程

 更新時(shí)間:2023年10月16日 14:48:52   作者:earlytrain9653  
這篇文章主要給大家介紹了關(guān)于Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)的相關(guān)資料,要在Java中實(shí)現(xiàn)微信掃碼登錄,您可以按照以下步驟進(jìn)行操作,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

1.登錄流程及原理

1.1 OAuth2協(xié)議

網(wǎng)站應(yīng)用微信登錄是基于OAuth2.0協(xié)議標(biāo)準(zhǔn)構(gòu)建的微信OAuth2.0授權(quán)登錄系統(tǒng)。 在進(jìn)行微信OAuth2.0授權(quán)登錄接入之前,在微信開放平臺注冊開發(fā)者帳號,并擁有一個(gè)已審核通過的網(wǎng)站應(yīng)用,并獲得相應(yīng)的 AppID 和 AppSecret,申請微信登錄且通過審核后,可開始接入流程。

方案流程:

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

OAuth2包括以下角色:

1、客戶端

本身不存儲資源,需要通過資源擁有者的授權(quán)去請求資源服務(wù)器的資源,比如:手機(jī)客戶端、瀏覽器等。

2、資源擁有者

通常為用戶,也可以是應(yīng)用程序,即該資源的擁有者。

A表示客戶端請求資源擁有者授權(quán)。

B表示資源擁有者授權(quán)客戶端訪問自己的用戶信息。

3、授權(quán)服務(wù)器(也稱認(rèn)證服務(wù)器)

認(rèn)證服務(wù)器對資源擁有者進(jìn)行認(rèn)證,還會對客戶端進(jìn)行認(rèn)證并頒發(fā)令牌。

C 客戶端攜帶授權(quán)碼請求認(rèn)證。

D認(rèn)證通過頒發(fā)令牌。

4、資源服務(wù)器

存儲資源的服務(wù)器。

E表示客戶端攜帶令牌請求資源服務(wù)器獲取資源。

F表示資源服務(wù)器校驗(yàn)令牌通過后提供受保護(hù)資源。

2.2 微信掃碼登錄流程

以瀏覽器上掃碼登錄為例:

認(rèn)證登錄流程:

1、用戶申請登錄網(wǎng)站,掃微信二維碼,請求微信授權(quán)登錄;

2、用戶確認(rèn)后,微信端會攜帶code重定向到該網(wǎng)站;

3、網(wǎng)站帶上code、appid、appsecret向微信端申請access_token;

4、微信返回access_token,網(wǎng)站帶上access_token向微信服務(wù)端獲取用戶信息;

5、網(wǎng)站拿到信息后重定向到登陸界面即登陸成功。

2.代碼實(shí)現(xiàn)

本項(xiàng)目認(rèn)證服務(wù)需要做哪些事?

1、需要定義接口接收微信下發(fā)的授權(quán)碼。

2、收到授權(quán)碼調(diào)用微信接口申請令牌。

3、申請到令牌調(diào)用微信獲取用戶信息

4、獲取用戶信息成功將其寫入本項(xiàng)目用戶中心數(shù)據(jù)庫。

5、最后重定向到瀏覽器自動(dòng)登錄。

代碼如下:

2.1 controller

@Controller
public class WxLoginController {

 @Autowired
 WxAuthServiceImpl wxAuthService;

 /**
  * 用戶掃碼確認(rèn)登錄后進(jìn)入該接口,收到wx端重定向傳過來的授權(quán)碼,用授權(quán)碼申請令牌,查詢用戶信息,寫入用戶信息
  * @param code 微信端返回的授權(quán)碼
  * @param state 用于保持請求和回調(diào)的狀態(tài),授權(quán)請求后原樣帶回給第三方。
  *              該參數(shù)可用于防止 csrf 攻擊(跨站請求偽造攻擊),建議第三方帶上該參數(shù),
  *              可設(shè)置為簡單的隨機(jī)數(shù)加 session 進(jìn)行校驗(yàn)
  * @return
  * @throws IOException
  */
  @RequestMapping("/wxLogin")
  public String wxLogin(String code, String state) throws IOException {

     //拿授權(quán)碼申請令牌,查詢用戶
   XcUser xcUser = wxAuthService.wxAuth(code);
   if(xcUser == null){
     //重定向到一個(gè)錯(cuò)誤頁面
     return "redirect:http://www.xxxxxxx.com/error.html";
   }else{
    String username = xcUser.getUsername();
    //重定向到登錄頁面,自動(dòng)登錄
     return "redirect:http://www.xxxxxxx.com/sign.html?username="+username+"&authType=wx";
   }
  }
}

2.2 WxAuthServiceImpl

這里直接用service實(shí)現(xiàn)類;

@Service("wx_authservice")
public class WxAuthServiceImpl implements AuthService {

    @Autowired
    UserMapper userMapper;
    @Value("${weixin.appid}")
    String appid;
    @Value("${weixin.secret}")
    String secret;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    WxAuthServiceImpl currentProxy;

    //拿授權(quán)碼申請令牌,查詢用戶
    public User wxAuth(String code) {
        //拿授權(quán)碼獲取access_token
        Map<String, String> access_token_map = getAccess_token(code);
        System.out.println(access_token_map);
        //得到令牌
        String access_token = access_token_map.get("access_token");
        //得到openid
        String openid = access_token_map.get("openid");
        //拿令牌獲取用戶信息
        Map<String, String> userinfo = getUserinfo(access_token, openid);
        System.out.println(userinfo);
        //添加用戶到數(shù)據(jù)庫
        User User = currentProxy.addWxUser(userinfo);

        return User;
    }

    @Transactional
    public User addWxUser(Map userInfo_map){

        //先取出unionid
        String unionid = (String) userInfo_map.get("unionid");
        //根據(jù)unionid查詢數(shù)據(jù)庫
        User User = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getWxUnionid, unionid));
        if(User!=null){
            //該用戶在系統(tǒng)存在
            return User;
        }
        User = new User();
        //用戶id
        String id = UUID.randomUUID().toString();
        User.setId(id);
        User.setWxUnionid(unionid);
        //記錄從微信得到的昵稱
        User.setNickname(userInfo_map.get("nickname").toString());
        User.setUserpic(userInfo_map.get("headimgurl").toString());
        User.setName(userInfo_map.get("nickname").toString());
        User.setUsername(unionid);
        User.setPassword(unionid);
        User.setUtype("101001");//學(xué)生類型
        User.setStatus("1");//用戶狀態(tài)
        User.setCreateTime(LocalDateTime.now());
        userMapper.insert(User);
        UserRole UserRole = new UserRole();
        UserRole.setId(UUID.randomUUID().toString());
        UserRole.setUserId(id);
        UserRole.setRoleId("17");//學(xué)生角色
        userRoleMapper.insert(UserRole);
        return User;

    }

    //請求微信獲取令牌

    /**
     * 微信接口響應(yīng)結(jié)果
     * {
     * "access_token":"ACCESS_TOKEN",
     * "expires_in":7200,
     * "refresh_token":"REFRESH_TOKEN",
     * "openid":"OPENID",
     * "scope":"SCOPE",
     * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     */
    private Map<String, String> getAccess_token(String code) {
        String url_template = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        String url = String.format(url_template, appid, secret, code);
        //請求微信獲取令牌
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, null, String.class);

        System.out.println(response);
        //得到響應(yīng)串
        String responseString = response.getBody();
        //將json串轉(zhuǎn)成map
        Map map = JSON.parseObject(responseString, Map.class);
        return map;
    }

    //攜帶令牌查詢用戶信息
    //http請求方式: GET
    //https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
    /**
     {
     "openid":"OPENID",
     "nickname":"NICKNAME",
     "sex":1,
     "province":"PROVINCE",
     "city":"CITY",
     "country":"COUNTRY",
     "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJfHe/0",
     "privilege":[
     "PRIVILEGE1",
     "PRIVILEGE2"
     ],
     "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"

     }
    */
    private Map<String,String> getUserinfo(String access_token,String openid) {
        //請求微信查詢用戶信息
        String url_template = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
        String url = String.format(url_template,access_token,openid);
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
        String body = response.getBody();
        //將結(jié)果轉(zhuǎn)成map
        Map map = JSON.parseObject(body, Map.class);
        return map;

    }
}

3.認(rèn)證授權(quán)

項(xiàng)目集成了Spring Security,還需從用戶信息中獲取該用戶的權(quán)限信息;

3.1 UserServiceImpl

重寫了Spring Security的用戶認(rèn)證方式,使其接入微信登錄認(rèn)證;

authParamsDto 認(rèn)證參數(shù)定義;

/**
 * @description 統(tǒng)一認(rèn)證入口后統(tǒng)一提交的數(shù)據(jù)
 */
@Data
public class AuthParamsDto {

    private String username; //用戶名
    private String password; //域  用于擴(kuò)展
    private String cellphone;//手機(jī)號
    private String checkcode;//驗(yàn)證碼
    private String checkcodekey;//驗(yàn)證碼key
    private String authType; // 認(rèn)證的類型   password:用戶名密碼模式類型    sms:短信模式類型
    private Map<String, Object> payload = new HashMap<>();//附加數(shù)據(jù),作為擴(kuò)展,不同認(rèn)證類型可擁有不同的附加數(shù)據(jù)。如認(rèn)證類型為短信時(shí)包含smsKey : sms:3d21042d054548b08477142bbca95cfa; 所有情況下都包含clientId
}

用戶擴(kuò)展信息定義;

/**
 * @description 用戶擴(kuò)展信息
 */
@Data
public class XcUserExt extends XcUser {
    //用戶權(quán)限
    List<String> permissions = new ArrayList<>();
}

loadUserByUsername()方法重寫,使其支持微信認(rèn)證;

@Slf4j
@Service
public class UserServiceImpl implements UserDetailsService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    MenuMapper menuMapper;//菜單權(quán)限mapper

    //傳入的是AuthParamsDto的json串
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        AuthParamsDto authParamsDto = null;
        try {
            //將認(rèn)證參數(shù)轉(zhuǎn)為AuthParamsDto類型
            authParamsDto = JSON.parseObject(s, AuthParamsDto.class);
        } catch (Exception e) {
            log.info("認(rèn)證請求不符合項(xiàng)目要求:{}",s);
            throw new RuntimeException("認(rèn)證請求數(shù)據(jù)格式不對");
        }
        //認(rèn)證方式,
        String authType = authParamsDto.getAuthType();
        //從spring容器中拿具體的認(rèn)證bean實(shí)例
        AuthService authService = applicationContext.getBean(authType + "_authservice", AuthService.class);
        //開始認(rèn)證,認(rèn)證成功拿到用戶信息
        UserExt UserExt = authService.execute(authParamsDto);

        return getUserPrincipal(UserExt);
    }
    //根據(jù)UserExt對象構(gòu)造一個(gè)UserDetails對象
    /**
     * @description 查詢用戶信息
     * @param user  用戶id,主鍵
     * @return 用戶信息
     */
    public UserDetails getUserPrincipal(UserExt user){

        //權(quán)限列表,存放的用戶權(quán)限
        List<String> permissionList = new ArrayList<>();

        //根據(jù)用戶id查詢數(shù)據(jù)庫中他的權(quán)限
        List<Menu> Menus = menuMapper.selectPermissionByUserId(user.getId());
        Menus.forEach(menu->{
            permissionList.add(menu.getCode());
        });
        if(permissionList.size()==0){
            //用戶權(quán)限,如果不加報(bào)Cannot pass a null GrantedAuthority collection
            permissionList.add("test");
        }

        String[] authorities= permissionList.toArray(new String[0]);
        //原來存的是賬號,現(xiàn)在擴(kuò)展為用戶的全部信息(密碼不要放)
        user.setPassword(null);
        String jsonString = JSON.toJSONString(user);
        UserDetails userDetails = User.withUsername(jsonString).password("").authorities(authorities).build();

        return userDetails;
    }

}

3.2 service接口

public interface AuthService {

  /**
   * @description 認(rèn)證方法
   * @param authParamsDto 認(rèn)證參數(shù)
   * @return 用戶信息
   */
  UserExt execute(AuthParamsDto authParamsDto);

}

上述execute()方法在微信登錄服務(wù)實(shí)現(xiàn)類WxAuthServiceImpl中實(shí)現(xiàn)

//微信認(rèn)證方法
    @Override
    public UserExt execute(AuthParamsDto authParamsDto) {
        //獲取賬號
        String username = authParamsDto.getUsername();
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername,username));
        if(user==null){
            throw new RuntimeException("用戶不存在");
        }
        UserExt userExt = new UserExt();
        BeanUtils.copyProperties(user, userExt);

        return userExt;
    }

3.3 自定義DaoAuthenticationProvider;

SpringSecurity框架默認(rèn)是密碼校驗(yàn)?zāi)J剑瑢⑵渲貙憺榭?,使其不再校?yàn)密碼;

@Slf4j
@Component
public class DaoAuthenticationProviderCustom extends DaoAuthenticationProvider {

 @Autowired
 @Override
 public void setUserDetailsService(UserDetailsService userDetailsService) {
  super.setUserDetailsService(userDetailsService);
 }

 @Override
 //不再校驗(yàn)密碼
 protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

 }

修改WebSecurityConfig類指定自定義的daoAuthenticationProviderCustom

@Autowired
    DaoAuthenticationProviderCustom daoAuthenticationProviderCustom;

    //使用自己定義DaoAuthenticationProviderCustom來代替框架的DaoAuthenticationProvider
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProviderCustom);
    }

至此我們基于Spring Security認(rèn)證流程修改為如下:

完成!

總結(jié)

到此這篇關(guān)于Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)的文章就介紹到這了,更多相關(guān)Java微信掃碼登錄認(rèn)證授權(quán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java定長隊(duì)列的實(shí)現(xiàn)示例

    java定長隊(duì)列的實(shí)現(xiàn)示例

    定長隊(duì)列是一種有限容量的隊(duì)列,對于某些應(yīng)用場景非常有用,本文主要介紹了java定長隊(duì)列的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • 如何在Java中使用正則表達(dá)式API

    如何在Java中使用正則表達(dá)式API

    這篇文章主要介紹了如何在Java中使用正則表達(dá)式API,我們將討論java正則表達(dá)式API,以及如何在Java編程語言中使用正則表達(dá)式。具體詳細(xì)介紹,需要的小伙伴可以參考下面文章內(nèi)容
    2022-06-06
  • IDEA中osgi的開發(fā)應(yīng)用指南詳解

    IDEA中osgi的開發(fā)應(yīng)用指南詳解

    這篇文章主要介紹了IDEA中osgi的開發(fā)應(yīng)用指南詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • java版數(shù)獨(dú)游戲界面實(shí)現(xiàn)(二)

    java版數(shù)獨(dú)游戲界面實(shí)現(xiàn)(二)

    這篇文章主要為大家詳細(xì)介紹了java版數(shù)獨(dú)游戲界面實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Java泛型變量如何添加約束

    Java泛型變量如何添加約束

    這篇文章主要介紹了Java泛型變量如何添加約束,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 詳解IDEA啟動(dòng)多個(gè)微服務(wù)的配置方法

    詳解IDEA啟動(dòng)多個(gè)微服務(wù)的配置方法

    這篇文章主要介紹了詳解IDEA啟動(dòng)多個(gè)微服務(wù)的配置方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • SpringBoot實(shí)現(xiàn)異步任務(wù)的項(xiàng)目實(shí)踐

    SpringBoot實(shí)現(xiàn)異步任務(wù)的項(xiàng)目實(shí)踐

    本文將使用SpringBoot 去實(shí)現(xiàn)異步之間的調(diào)用,提高系統(tǒng)的并發(fā)性能、用戶體驗(yàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • eclipse輸出Hello World的實(shí)現(xiàn)方法

    eclipse輸出Hello World的實(shí)現(xiàn)方法

    這篇文章主要介紹了eclipse輸出Hello World的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 用Java實(shí)現(xiàn)簡單ATM機(jī)功能

    用Java實(shí)現(xiàn)簡單ATM機(jī)功能

    這篇文章主要為大家詳細(xì)介紹了用Java實(shí)現(xiàn)簡單ATM機(jī)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 解決springboot中配置過濾器以及可能出現(xiàn)的問題

    解決springboot中配置過濾器以及可能出現(xiàn)的問題

    這篇文章主要介紹了解決springboot中配置過濾器以及可能出現(xiàn)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09

最新評論